1. 捕获变量的存续期
捕获变量的内容会保持到下次匹配成功为止,匹配失败后不会更改上次成功捕获时的变量内容,而匹配成功将重置这些捕获变量的值
所以说模式匹配总是出现在if或while条件表达式中
my $wilma = '123';
$wilma =~ /([0-9]+)/; # 匹配成功,$1的内容是123
$wilma =~ /([a-zA-Z]+)/; # 匹配失败,$1的内容仍是上次成功匹配的123
print "Wilma's word was $1... or was it?\n"; # 打印:Wilma's word was 123... or was it?
if($wilma =~ /([a-zA-Z]+)/){
print "Wilma's word was $1.\n";
} else {
print "Wilma doesn't have a word.\n";
}
因为捕获变量存在存续期,所以最好把捕获变量复制到某个普通变量里
if ($wilma =~ /([a-zA-Z]+)/){
my $wilma_word = $1;
...
}
在第9章中会学到怎么在模式匹配发生时,直接将捕获的内容存到变量,而不用另外对捕获变量进行赋值保存
2. 禁用捕获的括号
圆括号默认会捕获字符串到捕获变量中,有时候我们只希望用圆括号进行分组,但是不把捕获字符存到捕获变量中
不捕获括号(noncapturing parenthese),书写格式(?:)
,说明括号只用于分组,不再捕获匹配字符串
perl的正则表达式还有许多其它用在圆括号内的修饰符,比如前瞻、后顾、内嵌注释、在模式中嵌入运行程序等,可以看perlre文档来获取帮助信息
if(/(?:bronto)?saurus (steak|burger)/){
print "Fred wants a $1\n"; # 使用不捕获变量来跳过bronto
}
perl 5.22后,如果分组括号很多,而且都不需要捕获它们,可以在模式末尾使用\n
修饰符,它会把正则表达式中所有的圆括号都更改为非捕获分组
if(/(bronto)?saurus (BBQ )?(steak|burger)/n){
print "It matched\n"; # 现在捕获变量$1是undef
}
3. 命名捕获
可以对捕获内容直接命名,最终捕获到的内容会保存在特殊哈希%+
中,其中的键是捕捉时用的特殊标签,对应的值是被捕获的字符串
写法: (?<LABEL>PATTERN)
use v5.10;
my $names = 'Fred or Barney';
if( $names =~ m/(?<name1>\w+) (?:and|or) (?<name2>\w+)/){
say "I saw $+{name1} and $+{name2}"; # I saw Fred and Barney
}
引入捕获标签后,就可以随意移动为止并加入更多的捕获括号,不会因为捕获括号的次序变化带来不必要的麻烦(重新数自己的目的捕获内容是第几个捕获变量,其实很容易数错)
使用捕获标签后,反向引用的用法也有点变化,之前用\1
或者·\g{1}
这样的写法,现在可以使用\g{label}
这样的写法
\k<label>
等效于\g{label}
,不过它们2者间存在着细微差异
在2个以上的组有同名标签时,\k<label>
和\g{label}
总是指代最左边的那一组,但是\g{N}
可以实现相对反向引用
perl还支持python风格的语法,使用(?P<LABEL>PATTERN)
构造捕获分组后,可以用(?P=LABEL)
反向引用捕获的字符串
use v5.10;
my $names = 'Fred Flintstone and Wilma Flintstone';
if( $names =~ m/(?P<last_name>\w+) and \w+ (?P=last_name)/){
say "I saw $+{last_name}";
}
4. 自动捕获变量
有3个自动捕获的捕获变量
名称 | 保存内容 |
---|---|
$` | 匹配区段之前的内容 |
$& | 整个匹配区段 |
$’ | 匹配区段之后的内容 |
if("Hello there, neighbor" =~ /\s(\w+),/){
print "That was ($`)($&)($').\n"; # That was (Hello)( there, )( neighbor)
}
这3个自动捕获变量可能时空字符串,它们的存续期和一般的捕获变量一样,直到下次模式匹配成功
一旦在程序中某部分使用了自动捕获变量,其它正则表达式的运行速度也会跟着变慢
使用perl5.10或以上的版本,可以通过/p
修饰符,针对当前的正则表达式开启类似的自动捕获变量
名称 | 保存内容 |
---|---|
${^PREMATCH} | 匹配区段之前的内容 |
${^MATCH} | 整个匹配区段 |
${^POSTMATCH} | 匹配区段之后的内容 |
5. 优先级
正则表达式特性 | 示例 |
---|---|
圆括号(分组或捕获) | (PATTERN), (?:PATTERN), (?<LABEL>PATTERN) |
量词 | a*, a+, a?, a{n,m} |
锚位和字符序列 | abc, ^, $, \A, \b, \z, \Z |
择一 | a|b|c |
原子 | a, [abc], \d, \1, \g{2} |
6. 模式测试程序
下面这个程序可以用于检测某些字符串是否能被指定模式匹配以及在什么为止上匹配
while(<>){
chomp;
if(/YOUR_PATTERN_GOES_THERE/){
print "Matched: |$`<$&>$'|\n";
}else{
print "No match: |$_|\n";
}
}