Perl零宽断言

零宽断言概述

零宽断言概述

(?<=pattern) (?

?< lookbehind STRING < lookahead :负向 STRING 正向= :

Positive,肯定,表示匹配!  :Negative,否定,表示不匹配

(?=pattern) 零宽肯定正向预查(Zero-width positive lookahead),非获取匹配,从字符串右侧查找,须匹配pattern。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,即在一个匹配发生后,将继续从STRING之后开始下一次匹配的搜索,而不是从pattern之后开始。下同
(?!pattern) 零宽否定正向预查(Zero-width negative lookahead),非获取匹配,从字符串右侧查找,须不匹配pattern。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的"Windows"。
(?<=pattern) 零宽肯定负向预查(Zero-width positive lookbehind),非获取匹配,从字符串左侧查找,须匹配pattern。。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。
(? 零宽否定负向预查(Zero-width negative lookbehind),非获取匹配,从字符串左侧查找,须不匹配pattern。例如“(?

定义解释

零宽断言是正则表达式中的一种方法。正则表达式在计算机科学中,是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串。在很多文本编辑器或其他工具里,正则表达式通常被用来检索或替换那些符合某个模式的文本内容。许多程序设计语言都支持利用正则表达式进行字符串操作。

正向零宽断言

用于查找在某些内容(但并不包括这些内容)之前或之后的内容,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为 零宽断言。 断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

(?=exp)也叫零宽度正预测先行断言,其断言自身出现位置的后面(断言右侧)能匹配表达式exp。比如\b(?=re)\w+\b,匹配以re开头的单词的后面部分(除了re以外的部分),如查找reading a book时,它会匹配reading。

my $str = 'reading a book';
if($str =~ /\b(?=re)(\w+)/){
    print $1."\n"; # 输出reading
}

(?<=exp)也叫零宽度正回顾后向断言,其断言自身出现位置的前面(断言左侧)能匹配表达式exp。比如\b\w+(?<=ing\b)会匹配以ing结尾的单词的前半部分(除了ing以外的部分),例如在查找I am reading时,它匹配reading。

my $str = 'I am reading';
if($str =~ /(\w+)(?<=ing)\b/){
    print $1."\n"; # 输出reading
}

负向零宽断言

前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词,单词出现了字母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的单词。
同理,我们可以用(? 一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。()指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是之间的内容(再次提醒,不包括前缀和后缀本身)。

下面看一些例子加深理解:

(?=exp):零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。
匹配后面为_path,结果为product

'product_path'=~ /(\w+)(?=_path)/

(?<=exp):零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp

匹配前面为name:,结果为wangfei

'name:wangfei' =~ /(?<=name):(\w+)/;

(?!exp):零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp。

匹配后面不是_path

'product_path' =~ /(product)(?!_path)$/;
# 或者
'product_path' =~ /(\w+)(?

(?

# 匹配前面不是name:
'name:angelica' =~ /(?

详细介绍一个例子

'123456789'=~ /(?=(\d{3})+$)/

(?=(\d{3})+$) 单位匹配,每次都需要匹配到结尾才算成功,所谓g,就是从0的位置,开始遍历整个字符串

@123 456 789 ok 3个3位结尾
1@234 567 89
12@345 679 9
123@456 789 ok 2个3位结尾
1234@567 89
12345@678 9
123456@789 ok 1个3位结尾

/\B(?=(\d{3})+$)/g
\B的意思是,匹配前,检测当前位置左右是否同类型字符,如果不是,则停止匹配,继续下一次循环,
对于 123456789 而言:
第一次,0位置匹配时,左边是空格,右边是数字,因此是单词边界,失败, 也就是从1开始匹配。

最终的正则表达式为:

'123456789' =~ s/\B(?=(\d{3})+$)/,/g # 123,456,789

 

你可能感兴趣的:(Perl)