一、什么是正则表达式?

正则表达式就是用某种模式去匹配一类字符串的一种公式。


二、正则表达式的组成

在php中,正则表达式由三部分组成:分隔符、表达式和修饰符。

  • 分隔符:一般用:正斜线(/)、#、~或者%。
  • 表达式:由可以表示其他字符串的字符组成
  • 修饰符:可以开启或关闭某种功能(忽略大小写、多行匹配等)

    1.实例

    preg_match_all('%.*reg$%mi', $str, $arr);
    上面是一个php的正则表达式,参数为:
  1. 正则表达式
  2. 待匹配字符串
  3. 匹配到的字符串

三、测试工具

写出正则表达式就需要测试,测试工具很重要。一般来说,用在线正则匹配工具就可以满足要求,或者使用语言自带的正则函数。


四、元字符

26个字符可以组成任何单词。而元字符,可以通过组合去匹配到任何能见到的字符串。

元字符 描述
. 匹配除换行符以外的任意字符
\w 匹配字母、数字、下划线或者汉字
\s 匹配任意空白符
\d 匹配数字
\b 定界符:匹配单词开始或者结束
^ 匹配字符串开始
$ 匹配字符串结束
- 表示范围
[] 匹配括号中任一字符
* 量词:表示任意多个
+ 量词:一个或者多个
? 量词:一个或者没有
{} 量词:在括号范围之内
\W 匹配任意不是字母、数字、下划线或者汉字的字符
\S 匹配非空白的字符
\D 匹配非数字
\B 匹配非单词开始或者结束

五、匹配规则

1.字符组

[aeiou] 匹配括号中的任何一个字母

c[aou]t 匹配 cat/cot/cut 而不能匹配caout

[] 匹配单个字符

2.转义

元字符表示特殊的含义,如果想匹配元字符就需要用到转义。转义需要在需转义的字符钱加反斜线(\)。

(.)表示任意字符,而(.)则表示 . 这个字符
(\w)表示word、而(\w)则表示 \w 这个字符串

3.分支

分支就相当于编程时遇到了if语句。

[ch]at 可以匹配 cat/hat
(c|h|f|to)at 可以匹配 cat/hat/fat/toat

在匹配时、就相当于遇到了选择语句,需要判断之后再匹配
分支检测为if/else语句,遇到if中条件为真则不会继续匹配

4.分组

分组的作用就是将多个字符看做是一个整体。
. 表示任意字符重复任意次
(abc)
表示abc这个字符串以相同的顺序重复任意多次










































类别 语法 描述
捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
(?《name》exp) 匹配exp,并给匹配到的文本命名,也可以写成(?’name’exp)
(?:exp) 匹配exp并且不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
(?《=exp) 匹配exp后面的位置(英文小于号无法显示,用书名号代替)
(?!exp) 匹配后面跟的不是exp的位置
(?《!exp) 匹配前面不是exp的位置(英文小于号无法显示,用书名号代替)
注释 (?#comment) 提供注释,不对表达式产生影响

5.反向引用

\b(\w+)\b\s+\1\b

这个可以匹配 go go 或者 a a
\1 指的是在前面第一个捕获的分组

也可以使用这个 \k< Word >

\b(?< Word >\w+)\b\s+\k < Word > \b

6.环视

正则匹配有四种环视方式:

  • 顺序肯定环视(零宽度正预测先行断言)
  • 逆序肯定环视(零宽度正回顾后发断言)
  • 顺序否定环视(零宽度负预测先行断言)
  • 逆序否定环视(零宽度负回顾后发断言)

四种方式对应的表达式分别为:

  • (?=exp)
  • (?<=exp)
  • (?!exp)
  • (?<!exp)

乍一看确实很难理解,但是我这里有更好的理解方式:

  • 零宽度代表,匹配的时候只匹配位置,而不将匹配到的内容放到结果中
  • 正预测和正回顾则代表着,匹配到的位置存在是对的
  • 负预测和负回顾则代表着,匹配到的位置不存在才是对的(非)
  • 先行断言就像是你在预测一件事情,预测后面发生的就是这样的(在表达式后面发生)
  • 后发断言就像是事情已经发生了,然后才说出来这件事情(在表达式前面发生)

理解了以上几条之后,你就可以开始写复杂的正则表达式了。

例子:

(?<![a-z])\d{7} 前面不是小写字母的7位数字

7.贪婪、懒惰匹配

. 表示贪婪匹配,能匹配更多就匹配多个
.
? 表示懒惰匹配,在能匹配更多个的时候优先不匹配

懒惰限定符 描述
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

六、模式

1.忽略大小写(i)

一般忽略大小写时为全局生效,若想部分生效需要如此:

#ab(?i)c#

此表达式会匹配abc和abC

2.多行模式(m)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// 多行模式的本质是检查是否有 \n 换行符
$source1 = 'abc\nabcd';
$source2 = "abc\nabcd";
if (preg_match_all('%^abc%m', $source1, $arr)) {
echo "匹配成功--";
var_dump($arr);
} else {
echo "匹配不成功--";
}
if (preg_match_all('%^abc%m', $source2, $arr)) {
echo "匹配成功--";
var_dump($arr);
} else {
echo "匹配不成功";
}

3.点号通配模式

点号通配模式的作用是使正则表达式的点号元字符能匹配换行符,如果没有这个修饰符,点号不匹配换行符。

1
2
3
4
5
6
7
8
9
10
11
// 点号通配模式(s),使点号可以匹配换行符
$str = "<body><div class='content'>
<div class='head'></div>
<div class='body'></div>
<div class='foot'></div>
</div></body>";
$arr1 = $arr2 = array();
preg_match_all('%<body>(.*)<\/body>%', $str, $arr1);
var_dump($arr1); // 为空
preg_match_all('%<body>(.*)<\/body>%s', $str, $arr2);
var_dump($arr2); // 匹配成功

4.懒惰模式(U)

加上懒惰模式,相当于在.*后面加上问号。

5.结尾限制(D)

加上结尾限制,则结尾不能有换行符

6.支持UTF-8转义表达(u)

启用u模式,模式字符串被当成utf-8。php4.1可用。

1
2
3
4
5
6
7
// 支持 UTF-8 转义表达 (u)
$str = "php 编程";
if (preg_match("/^[\x{4e00}-\x{9fa5}]+$/u", $str)) {
echo "该字符串都是中文";
} else {
echo "该字符串不全是中文";
}

七、实例

1.匹配email

\w{3,16}@\w{1,64}\.\w{2,5}

2.匹配手机号码

1\d{10}

3.将UBB标签解析成HTML

1
2
3
4
5
6
<?php
$str = '[url]1.gif[/url][url]2.gif[/url][url]3.gif[/url]';
$reg = "#\[url\](.*?)\[\/url\]#"; // 此处使用懒惰模式匹配,否则会一直匹配到最后的标签
$s = preg_replace($reg, "<img src='http://image.baidu.com/$1'>", $str);
echo $s;

八、其他

1.与:

  • abc
  • 肯定环视

    2.或:

  • a?
  • 字符组

    3.非:

  • ^a
  • \D \W \B
  • 否定环视

4.优先级

从大到小

  1. 转义符 \
  2. 括号和中括号
  3. 量词限定符 */+/?等
  4. 定位点和序列 ^/$/ 元字符、连字符
  5. 替换 |