正则表达式零宽断言(环视)

正则表达式30分钟入门教程 中称为零宽断言

《精通正则表达式》一书中称为环视,所以环视和断言是说的是一回事,只是不同的叫法而已

 

下面是零宽断言的几个例子:

$str = 'by ttabdef';
 
//1、(?:exp) 匹配exp但是不捕获
preg_match('/(?:ab)def/', $str, $match1);/*array([0] => abdef)*/
 
//2、(?=exp)断言自身出现的位置的后面能匹配表达式exp
$str1 = 'dancing';
preg_match('/\w+(?=ing)/', $str1, $t1);//array([0] => danc)
preg_match('/tt(?=ab)ab/', $str, $match2);//Array([0] => ttab)
 
//3、(?<=exp)断言自身出现位置的前面能匹配正则表达式, js不支持该写法
preg_match('/(?<=ab)def/', $str, $match3);//array([0] => def)
preg_match('/(?<=c)def/', $str, $t2);//array()
 
//4、(?!exp)断言自身出现位置的后面不能匹配正则表达式
preg_match('/tt(?!c)/', $str, $match4);//array([0] => tt)
 
//5、(?<!exp)断言自身出现位置的前面不能匹配正则表达式, js不支持该写法
preg_match('/(?<!c)def/', $str, $t3);//array([0] => def)

//6、(?<name>exp)   匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)

在提数时会遇到这种情况:

原sql中:keyword != "http://css.cn.msn.com/msntoday/default.html"  and
        keyword != "http://css.cn.msn.com/msntoday/dictoday/default.shtml" and
        keyword != "http://css.cn.msn.com/msntoday/default_dict.html"

正则写的话,就用到负向零宽断言,如下:

$regex = '/(?<!css.cn.msn.com/msntoday/(default|dictoday/default|default_dict)\\.[s]?html$/i'

有一点需要注意,在PHP中逆序环视只能匹配固定长度的文本。不可以使用(?<=books?) 、 (?<=\w+)  或 (?=\d{2,3})
提数时也会遇到如下情况:

原sql中:(keyword like "%.html" or keyword like "%.shtml") and  (keyword NOT LIKE "%.ynet.com%")

但是不能用如下正则:

$regex = '/(?<!ynet.com).*[s]?html/i'
$regex1 = '/(?<!ynet\.com)\/.*[s]?html$/i';

不过以下正则能达到预想效果

$regx = '/(?<!ynet)\.com.*[s]?html/i';

 说一下个人对于逆向否定环视的理解:

$url = 'http://www.ynet.com/a/b/c/d.shtml';

$regex = '/(?<!ynet\.com)\/.*[s]?html$/i';

匹配结果是://www.ynet.com/a/b/c/d.shtml

感觉正则内部将这个正则进行了分组,①(?<!ynet\.com)②\/.*[s]?html$,

正则引擎首先对②进行匹配,不匹配②则不再匹配①,匹配②定位斜线"/"位置,然后判断左侧是否存在ynet.com

同理:$regx = '/(?<!ynet)\.com.*[s]?html/i'; 首先判断是否匹配.com.*[s]?html,如果匹配则定位.com的位置,然后判断左侧是否为ynet,否则停止匹配,

 逆向肯定环视

$str= '<div id="a">a test</div>';
preg_match('/(?<=>).*(?=<\/div>)/', $str, $matches);
匹配结果是:a test

肯定环视时应该是顺序匹配,直到匹配到字符串结尾为止

 

 环视功能介绍,参考以下博客:

http://blog.csdn.net/lxcnn/article/details/4954134

该博客用.NET实现了以下这个问题

前几天在CSDN论坛遇到这样一个问题。

我要通过正则分别取出下面 <font color="#008000"> 与 </font> 之间的字符串

1、在 <font color="#008000"> 与 </font> 之间的字符串是没法固定的,是随机自动生成的

2、其中 <font color="#008000"> 与 </font>的数量也是没法固定的,也是随机自动生成的

<font color="#008000"> ** 这里是不固定的字符串1 ** </font>

<font color="#008000"> ** 这里是不固定的字符串2 ** </font>

<font color="#008000"> ** 这里是不固定的字符串3 ** </font>

PHP实现方法如下:

$str = '<font color="#008000"> ** 这里是不固定的字符串1 ** </font>
<font color="#008001"> ** 这里是不固定的字符串2 ** </font>
<font color="#008002"> ** 这里是不固定的字符串3 ** </font>';

//preg_match_all('/(?<=<font color="#\d{6}">).*?(?=<\/font>)/s', $s3, $matches);
preg_match_all('/(?<=<font).*>(.*)(?=<\/font>)/Us', $str, $matches);
var_dump($matches);
/*
 * array (size=2)
  0 => 
    array (size=3)
      0 => string ' color="#008000"> ** 这里是不固定的字符串1 ** ' (length=56)
      1 => string ' color="#008001"> ** 这里是不固定的字符串2 ** ' (length=56)
      2 => string ' color="#008002"> ** 这里是不固定的字符串3 ** ' (length=56)
  1 => 
    array (size=3)
      0 => string ' ** 这里是不固定的字符串1 ** ' (length=39)
      1 => string ' ** 这里是不固定的字符串2 ** ' (length=39)
      2 => string ' ** 这里是不固定的字符串3 ** ' (length=39)
*/

 

 

 

 

posted @ 2014-07-02 16:10  1317660800  阅读(466)  评论(0)    收藏  举报