qr//创建正则对象
因为可以在正则模式中使用变量替换,所以我们可以将正则中的一部分表达式事先保存在变量中。例如:
$str="hello worlds gaoxiaofang";
$pattern="w.*d";
$str =~ /$pattern/;
print "$&\n";
但是,这样缺陷很大,在保存正则表达式的变量中存放的特殊字符要防止有特殊意义。例如,当使用m//的方式做匹配分隔符时,不能在变量中保存/,除非转义。
perl提供了qr/pattern/的功能,它把pattern部分构建成一个正则表达式对象,然后就可以:
在正则表达式中直接引用这个对象
可以将这个对象保存到变量中,通过引用变量的方式来引用这个已保存好的正则对象
将引用变量插入到其它模式中构建更复杂的正则表达式
其中:
qr//的定界符斜线可以替换为其它符号,例如对称的括号类qr() qr{} qr<> qr[],一致的符号类qr%% qr## qr!! qr$$ qr"" qr''等。
但是使用单引号作为定界符时比较特殊(即qr'pattern'),它会将pattern部分使用单引号的方式去解析,例如变量$var无法替换,而是表示4个字符。但是正则表达式的元字符仍然起作用,例如$仍然表示行尾。
$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";
还允许为这个正则对象设置修饰符,比如忽略大小写的匹配修饰符为i,这样在真正匹配的时候,就只有这一部分正则对象会忽略大小写,其余部分仍然区分大小写。
$str="HELLO wORLDs gaoxiaofang";
$pattern=qr/w.*d/i; # 忽略大小写
$str =~ /HEL.* $pattern/; # 匹配成功,$pattern部分忽略大小写
$str =~ /hel.* $pattern/; # 匹配失败
$str =~ /hel.* $pattern/i; # 匹配成功,所有都忽略大小写
qr如何构建正则对象
输出qr构建的正则引用,看看是怎样的结构:
$patt1=qr/w.*d/;
print "$patt1\n";
$patt2=qr/w.*d/i; # 加上修饰符i
print "$patt2\n";
$patt3=qr/w.*d/img; # 加上修饰符img
print "$patt3\n";
上面的print将输出如下结果:
(?^:w.*d)
(?^i:w.*d)
(?^mi:w.*d)
qr的作用实际上就是在我们给定的正则pattern基础上加上(?^:)并带上一些修饰符,得到的结果总是(?^FLAGS:pattern)。
但是上面patt3的修饰符g不见了。先可以看看(?^:)的作用:非捕获分组,并重置修饰符。重置为哪些修饰符?对于(?^FLAGS:)来说,只有这些修饰符"alupimsx"是可用的,即(?^alupimsx:):
如果给定的修饰符不在这些修饰符内,则不被识别,有时候会报错
如果给定的修饰符属于这几个修饰符,那么没有给定的修饰符部分将采用默认值(不同版本可能默认是否开启的值不同)
所以上面的g会被丢弃,甚至在进一步操作这个正则引用时,会报错。
既然qr给pattern部分加上了(?^:),那么当它们插入到其它正则中的时候,就能保证这一段是独立的,不受全局修饰符影响的模式。
$patt1=qr/w.*d/im;
$patt2=qr/hel.*d $patt1/i;
print "$patt2\n"; # 输出:(?^i:hel.*d (?^mi:w.*d))
正则引用作为标量的用法
既然qr//创建的正则对象引用是一个标量,那么标量可以出现的地方,正则引用就可以出现。例如,放进hash结构,数组结构。
例如,放进数组中形成一个正则表达式列表,然后给定一个待匹配目标,依次用列表中的这些模式去匹配。
use v5.10.1;
my @patterns = (
qr/(?:Willie )?Gilligan/,
qr/Mary Ann/,
qr/Ginger/,
qr/(?:The )?Professor/,
qr/Skipper/,
qr/Mrs?. Howell/,
);
my $name = 'Ginger';
foreach my $pattern ( @patterns ) {
if( $name =~ /$pattern/ ) {
say "Match!";
print "$pattern";
last;
}
}
还可以将这些正则引用放进hash中,为每个pattern都使用key来标识一下,例如pattern1是用来匹配什么的:
use v5.10.1;
my %patterns = (
Gilligan => qr/(?:Willie )?Gilligan/,
'Mary Ann' => qr/Mary Ann/,
Ginger => qr/Ginger/,
Professor => qr/(?:The )?Professor/,
Skipper => qr/Skipper/,
'A Howell' => qr/Mrs?. Howell/,
);
my $name = 'Ginger';
my( $match ) = grep { $name =~ $patterns{$_} } keys %patterns;
say "Matched $match" if $match;
上面将grep语句的结果赋值给了一个标量,所以如果有多个Pattern能匹配$name,多次执行,$match的值将可能会不一样。
构建复杂的正则表达式