正则表达式 是一种用来描述一定数量文本的模式,通过定义好的正则语句能匹配到目标文本集中所想要的文本。

    比如要在文本"her phone number is 111-1111-1111"  中取到电话号码,首先知道电话的格式:1开头加上2个数字加上-加上4个数字加上-加上4个数字。这些规则就可以来写正则表达式了: '/1[\d]{2}-[\d]{4}-[\d]{4}/'。    //的中间就是正则表达式。[]中是字符集\d,表示的是任意数字,而{2}{4}则分别代表匹配前面的字符几次。下面系统地整理下正则表达式的使用方法:   

 

一.字符集

    1. []: 字符集:中括号中的是想匹配的字符的集合.

    如:/[abc]/的作用相当于匹配a字符或b字符或c字符,与/a|b|c/作用相同,顺便一说,|的意义是或。

        []的后面也可以加上{time},来表示对这字符集匹配time次。  

        []中若字符的类型相同,顺序连贯,也可以用'-'符号将首尾连起来。如'/[a-z][a-h][A-Z][0-9]/'代表匹配第一个字符在a到z的26个字母中,第二个字符在a到h的8个字母中,第三个字符是0到9的10个数字中。

    2. [^]: 取反字符集:匹配所有不在括号中出现的字符。

    如/[^a]/ 匹配所有非a字符。用法可以参考字符集[]的用法,只是效果是取反的。

    3. ^    从文本的开始处匹配    如:'/^abc/'    匹配以abc为开始的文本

    4. $    从文本的结束处匹配    如:'/abc$/'    匹配以abc为结束的文本


二.简化字符集

   字符集可以按规律划分为以下几类,使用简化字符集可以提高写正则的效率。

   1. \d :数字字符集,匹配数字。   相当于[0-9]

   2. \s :任意的空白符             相当于[ ]

   3. \w: 数字或子母或下划线。     相当于[0-9a-zA-Z_]

   4. .   除换行符以外的任意字符。 相当于[^\n\r]

   5. \b  匹配单词的开始或结束     \babc\b 匹配文本'this is  abc'中的单词abc

   6  \D  任意非数字字符           相当于[^0-9]

   7. \S  任意非空白字符           相当于[^ ]

   8. \W  任意不是字母数字或下划线的字符

   9. \B  任意不是单词的开头或结尾


三.匹配次数

1.  +    一次或多次。     如 /a+/ 可以匹配a, aa, aaa, aaaa....

   2.  *    0次或多次。 

3.  ?    0次或一次。

   4. {n}   n次

   5. {n,}  n次或n次以上

   6. {n,m} n到m次


四. 懒惰限制符

   1. *?    重复任意次,但尽量少次。   相当于*的最少匹配次数  相当于'/a+?/' 匹配'aaaa'时会匹配出a

   2. +?    重复一至多次,尽量少次。   相当于+的最少匹配次数

   3. ??    重复0次到1次,尽量少次。

   4. {n,}?  重复n次或n次以上,尽量少次。

   5. {n,m}? 重复n到m次,尽量少次。

    

五.组与向后引用

    正则表达式中用()括起来的部分所匹配到的文本会分到单独的组中,若没名字则默认从1开始递增的值为组名,有设置名字的组则以名字为组名(如2所述),而且还能以组名代表式子向后引用:

    1.  普通捕获:

     '/(exp)\1/'     exp表示的是表达式,\1代表的是在xp式子匹配到的文本。

     如:'/([\w]{3}).*\1/'  表示是匹配到3个数字或字符或下划线组成的文本,存入组1中,中间匹配任意字符任意次数,后面再匹配组1中的文本,能匹配到的格式是: 'abcdefabc','d_1d_1',组1存的是'abc','d_1',而后面组1又出现了,所以整个文本匹配成功。

    2.  命名捕获

      '/(?<name>exp)\k<name>/' 也可以写成"/(?'name'exp)\k'name'/"   与上1类似,将捕获的文本保存在组name中。name可以自己命名。

    而组的作用是什么呢?php中的preg_match_all()方法中可以看到用处:

echo '<pre>';
        $str = 'yes, that is ok!';                            //文本
        $repex = '/(?<anser>ok).*\k<anser>/';                //正则表达式   如果匹配到ok,则分配到anser组中
        $count = preg_match_all($repex, $str, $match);       //匹配成功次数
        var_dump($count);                                    //1
        var_dump($match);                                    //匹配结果集: array('0'=>'ok!','anser'=>'ok','1'=>'ok')
        var_dump($match['anser']);                           //匹配结果集中的anser组
        echo '<pre>';
        $str = 'yes, that is ok!';                            //文本
        $repex = '/(?<anser>ok).*\k<anser>/';                //正则表达式   如果匹配到ok,则分配到anser组中
        $count = preg_match_all($repex, $str, $match);       //匹配成功次数
        var_dump($count);                                    //1
        var_dump($match);                                    //匹配结果集: array('0'=>'ok!','anser'=>'ok','1'=>'ok')
        var_dump($match['anser']);                           //匹配结果集中的anser组

       从结果看到,匹配成功的次数是1次,而且文本组有2个,一个是默认的1,一个是设置的anser.

       组的作用还可以引用在替换式中,如php中的preg_replace():

$repex = '/.*([\w]{3,}\.[\w]+\.[\w]{2,3})/';
        $str = 'link = www.example.com';
        $urlTag = preg_replace($repex, "<a href='\\1'>", $str);  //将$str的内容替换成"<a href='\\1'>",\\1则代表正则中的分组1
        var_dump($urlTag);                                       //结果 :string '<a href='www.example.com'>' (length=26)
        $repex = '/.*([\w]{3,}\.[\w]+\.[\w]{2,3})/';
        $str = 'link = www.example.com';
        $urlTag = preg_replace($repex, "<a href='\\1'>", $str);  //将$str的内容替换成"<a href='\\1'>",\\1则代表正则中的分组1
        var_dump($urlTag);                                       //结果 :string '<a href='www.example.com'>' (length=26)

     在这里注意的是""中的引用需要多加一个\则组1变成\\1,而' '号中则还是\1。

     3. 不分组不引用式括号

     (?:exp)   有些表达式只是需要括号将内容括起来当一个小整体,这时用这种方法括起来就不会产生分组和引用,减少资源的浪费。

     4. 零宽断言

     (?=exp)     匹配exp表达式前面的内容,即以exp结尾的内容但又不包括exp。

     (?<=exp)    匹配exp表达式后面的内容,即以exp开始的内容但又不包括exp。

     5. 负向零宽断言

     (?!exp)     匹配不是以exp结尾的内容。

     (?<!exp)    匹配不是以exp开始的内容。

     6. 注释

     (?#comment) 括号中的comment对表达式并无影响,只是注释作用。


六. 处理选项

    1. i    匹配时不区分字母大小写。 如'/text/i'    能匹配到TeXt

多行模式  更改^和$的含义, 使它们分别在任意一行的行首和行尾匹配,而不仅仅在字符串的开关和结尾匹配,在此状态下$的含义是匹配\n之前的位置及字符串结束前的位置 。

          如  : 用 '/\w$/m'  匹配文本 "abc\nabc\n"的匹配结果:c, c .(2次换行前的c都匹配到)。不加m,结果c

s    单行模式.  更改'.'的含义,使它与每个字符依次匹配,包括换行符\n(.本来是匹配除换行符以外的文本)


注意:

     1. 正则表达式中有特殊字符:( )[ ] \ ^ $ . ? + * | 想匹配这些字符的本体,需要加上\来换码。

     2. 正则表达式用单引号与双引号括时有些细节会有差别,双引号括时,引用分组如\1得写成\\1,而单引号则是\1。

     3. 字符串中有\n\r\t等特殊字符时,需用双引号。

     4. 匹配次数的重叠需谨慎,如'/([\w]{3}){4,6}/'  所代表的是匹配12到18次的\w