固化分组看上去挺简单的,此处也仅介绍了它最简单的形式。但实际上固化分组很复杂,它涉及了非常复杂的正则引擎匹配原理和回溯机制。如果有兴趣,可以阅读《精通正则表达式》一书的第四章。
环视锚定(断言)"环视"锚定,即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...\Eperl中的\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";