Perl正则表达式超详细教程(11)

固化分组看上去挺简单的,此处也仅介绍了它最简单的形式。但实际上固化分组很复杂,它涉及了非常复杂的正则引擎匹配原理和回溯机制。如果有兴趣,可以阅读《精通正则表达式》一书的第四章。

环视锚定(断言)

"环视"锚定,即lookaround anchor,也称为"零宽断言",它表示匹配的是位置,不是字符。

(?=...):表示从左向右的顺序环视。例如(?=\d)表示当前字符的右边是一个数字时就满足条件

(?!...):表示顺序环视的取反。如(?!\d)表示当前字符的右边不是一个数字时就满足条件

(?<=...):表示从右向左的逆序环视。例如(?<=\d)表示当前字符的左边是一个数字时就满足条件

(?<!)...:表示逆序环视的取反。如(?<!\d)表示当前字符的左边不是一个数字时就满足条件

关于"环视"锚定,最需要注意的一点是匹配的结果不占用任何字符,它仅仅只是锚定位置。

例如"your name is longshuai MA"和"your name is longfei MA"。使用(?=longshuai)将能锚定第一个句子中单词"longshuai"前面的空字符,但它的匹配结果是"longshuai"前的空白字符,所以(?=longshuai)long才能代表"long"这几个字符串,所以仅对于此处的两个句子,long(?=shuai)和(?=longshuai)long是等价的。

一般为了方便理解,在顺序环视的时候会将匹配内容放在锚定括号的左边(如long(?=longshuai)),在逆序环视的时候会将匹配的内容放在锚定括号的右边(如(?<=long)shuai)。

另外,无论是哪种锚定,都是从左向右匹配再做回溯的(假设允许回溯),即使是逆序环视。

例如:

$str="abc123abcc12c34"; # 顺序环视 $str =~ /a.*c(?=\d)/; # abc123abcc12c print "$&\n"; # 顺序否定环视 $str =~ /a.*c(?!\d)/; # abc123abc print "$&\n"; # 逆序环视,这里能逆序匹配成功,靠的是锚定括号后面的c $str =~ /a.*(?<=\d)c/; # abc123abcc12c print "$&\n"; # 逆序否定环视 $str =~ /a.*(?<!\d)c/; # abc123abcc print "$&\n";

逆序环视的表达式必须只能表示固定长度的字符串。例如(?<=word)或(?<=word|word)可以,但(?<=word?)不可以,因为?匹配0或1长度,长度不定,它无法对左边是word还是wordx做正确判断。

$str="hello worlds Gaoxiaofang"; $str =~ /he.*(?<=worlds?) Gao/; # 报错 $str =~ /he.*(?<=worlds|world) Gao/; # 报错

在PCRE中,这种变长的逆序环视锚定可重写为(?<=word|words),但perl中不允许,因为perl严格要求长度必须固定。

\Q...\E

perl中的\Q...\E用来强制包围一段字符,使得里面的正则符号都当做普通字符,不会有特殊意义,它是一种非常强的引用。但注意,它无法强制变量的替换。

例如:

$sub="world"; $str="hello worlds gaoxiaofang"; $str =~ /\Q$sub\E/; # $sub会替换,所以匹配成功world $str =~ /\Q$sub.\E/; # 元字符"."被当做普通的字符,所以无法匹配 qr//创建正则对象

因为可以在正则模式中使用变量替换,所以我们可以将正则中的一部分表达式事先保存在变量中。例如:

$str="hello worlds gaoxiaofang"; $pattern="w.*d"; $str =~ /$pattern/; print "$&\n";

但是,这样缺陷很大,在保存正则表达式的变量中存放的特殊字符要防止有特殊意义。例如,当使用m//的方式做匹配分隔符时,不能在变量中保存/,除非转义。

perl提供了qr/pattern/的功能,它把pattern部分构建成一个正则表达式对象,然后就可以在正则表达式中直接引用这个对象,更方便的是可以将这个对象保存到变量中,通过引用变量的方式来引用这个已保存好的正则对象。

$str="hello worlds gaoxiaofang"; # 直接作为正则表达式 $str =~ qr/w.*d/; print "$&\n"; # 保存为变量,再作为正则表达式 $pattern=qr/w.*d/; $str =~ $pattern; # (1) $str =~ /$pattern/; # (2) print "$&\n"; # 保存为变量,作为正则表达式的一部分 $pattern=qr/w.*d/; $str =~ /hel.* $pattern/; print "$&\n";

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e1a716f6fc1f35a6ad219d4af05ea1f5.html