您的位置:首页 > 其它

零宽断言

2011-06-03 18:13 169 查看

零宽断言

地球人,是不是觉得这些术语名称太复杂,太难记了?我也有同感。知道有这么一种东西就行了,它叫什么,随它去吧!人若无名,便可专心练剑;物若无名,便可随意取舍……
接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像/b

,^

,$

那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言

。最好还是拿例子来说明吧:

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
(?=exp)

也叫零宽度正预测先行断言

,它断言自身出现的位置的后面能匹配表达式exp

。比如/b/w+(?=ing/b)

,匹配以ing结尾的单词的前面部分(除了ing以外的部分)

,如查找I'm singing while you're dancing.

时,它会匹配sing

和danc



(?<=exp)

也叫零宽度正回顾后发断言

,它断言自身出现的位置的前面能匹配表达式exp

。比如(?<=/bre)/w+/b

会匹配以re开头的单词的后半部分(除了re以外的部分)

,例如在查找reading a book

时,它匹配ading



假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=/d)/d{3})+/b

,用它对1234567890

进行查找时结果是234567890



下面这个例子同时使用了这两种断言:(?<=/s)/d+(?=/s)

匹配以空白符间隔的数字(再次强调,不包括这些空白符)



负向零宽断言

前面我们提到过怎么查找不是某个字符或不在某个字符类里

的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它

时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

/b/w*q[^u]/w*/b

匹配包含后面不是字母u的字母q

的单词

。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq

,Benq

,这个表达式就会出错。这是因为[^u]

总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]

将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的/w*/b

将会匹配下一个单词,于是/b/w*q[^u]/w*/b

就能匹配整个Iraq fighting

。负向零宽断言

能解决这样的问题,因为它只匹配一个位置,并不消费

任何字符。现在,我们可以这样来解决这个问题:/b/w*q(?!u)/w*/b



零宽度负预测先行断言

(?!exp)

,断言此位置的后面不能匹配表达式exp

。例如:/d{3}(?!/d)

匹配三位数字,而且这三位数字的后面不能是数字

;/b((?!abc)/w)+/b

匹配不包含连续字符串abc的单词



同理,我们可以用(?<!exp)

,零宽度负回顾后发断言

来断言此位置的前面不能匹配表达式exp

:(?<![a-z])/d{7}

匹配前面不是小写字母的七位数字



请详细分析表达式(?<=<(/w+)>).*(?=<///1>)

,这个表达式最能表现零宽断言的真正用途。
一个更复杂的例子:(?<=<(/w+)>).*(?=<///1>)

匹配不包含属性的简单HTML标签内里的内容

。(?<=<(/w+)>)

指定了这样的前缀

:被尖括号括起来的单词

(比如可能是<b>),然后是.*

(任意的字符串),最后是一个后缀

(?=<///1>)

。注意后缀里的//

,它用到了前面提过的字符转义;/1

则是一个反向引用,引用的正是捕获的第一组

,前面的(/w+)

匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: