print "Do you like Perl?";
my $likes_perl = (<STDIN> =~ /\byes\b/i);
…… #耗时的其它程序……
if($likes_perl){
print "You said earlier that you like Perl,so..\n";}
批注:除非while循环的条件表达式中只有整行输入操作符(<STDIN>),否则输入行不会自动存入$_。因为绑定操作符的优先级相当高,也就没必要用圆括号来跨住模式测试表达式。所以下面这一行如同上面的表达式一样,会将匹配结果(而非输入的内容)存进变量。my $likes_perl = <STDIN> =~ /\byes\b/i; 5、模式串中的内插
#!/usr/bin/perl -w
my $what = "larry";
while(<>){
if(/^($what)/){
print "We saw $what in beginning of $_";}}
批注:不管$what的内容是什么,当我们进行模式匹配的时候,该模式都会成为$what的值。在这里它和/^(larry)/是相同的意思,也就是在每行的开头寻找larry。 6、模式中变量的存储 (1)捕获变量
匹配变量(包括自动匹配变量和带编号的匹配变量)最常用在替换运算中。圆括号同时也启动了正则表达式处理引擎的捕获功能。即把(圆括号中模式所匹配的)部分字符串暂时记下来的能力。如果有一对以上的圆括号,就会有一次以上的捕获。
每个被捕获的对象是原本的字符串,而不是模式。因为捕获变量存储的都是字符串,所以它们都是标量变量。在Perl里,它们的名字类似$1或者$2。模式里的括号有多少对,匹配变量就有多少个。如$4就是第四对括号捕获的字符串。这些变量能够取出字符串里的某些部分,因此是正则表达式威力强大的重要原因之一。
$_="Hello there,neighbor";
if(/\s(\w+),/){ #捕获空白符和逗号之间的单词
print "the word was $1\n;"
批注:打印the word was there
也可以一次捕获多个串。
$_="Hello there,neighbor";
if(/(\S+) (\S+), (\S+)/){ #捕获空白符和逗号之间的单词
print "the word was $1 $2 $3\n;"}
批注:让我们知道这些单词是Hello there neighbor。注意逗号的处理
my $dino="I fear that I'll be extinct after 1000 years.";
if($dino =~ /(\d*) years/){
print "That said '$1' years.\n"; #$1为1000
my $dino="I fear that I'll be extinct after a few million years.";
if($dino =~ /(\d*) years/){
print "That said '$1' years.\n";
批注:$1为空字符串,而不是尚未定义。若模式中有三个一下的圆括号,$4才会是undef (2)捕获变量的生命期
这些捕获变量通常能存活到下次成功的模式匹配为止。也就是说,失败的匹配不会改动上次成功匹配时捕获的内容,而成功的匹配会将它们重置。如果对比失败,它会输出可能遗留在$1里的任何字符串。
$wilma = ~ /(\w+)/; #不对!这里的结果不一定正确
print "Wilma's word was $1...or was it?\n";
批注:这就是为什么模式匹配总是出现在if或while条件表达式里:
if($wilma =~ /(\w+)/){
print "Wilma's word was $1.\n";}
else{
print"Wilma doesn't have a word.\n";}
因为捕获的内容不会永久留存,所以匹配变量只应该在模式匹配后的数行内使用。通常最好的做法是将它复制到某个一般的变量里。后面有更好的处理办法,即模式匹配发生时,直接将捕获的内容存到变量中。
if($wilma =~ /(\w+)/){
my $wilma_word = $1;...} (3)不捕获模式
现在是每个括号的内容都会被变量捕获,也可以设置某一个括号里的内容不被捕获。
if(/(?:bronto)?saurus (steak|burger)/){
print "Fred wants a $1\n";}
批注:这样增减选项的时候就不用修改捕获变量的名字了
if(/(?:bronto)?saurus (?:BBQ)?(steak|burger)/){
print "Fred wants a $1\n";} (4)命名捕捉
以上的变量捕捉方式有不好的地方。即使对于较为简单的模式来说,管理这样的数字变量也是比较困难的。如下例:
use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) and (\w+)){ #不会匹配
say "I saw $1 and $2";}
批注:不会看到say的输出,因为模式里的and和实际变量中的or不匹配。我们考虑后认为两者可以并存,加入“择一”来匹配and或者or。当然需要在模式中加入一对括号。
use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) (and|or) (\w+)){
say "I saw $1 and $2";}
批注:现在可以匹配了,但由于第二个括号的引入,是$2变量中的内容不是我们期望的了,期望的则进入了$3。打印输出I saw Fred and or,当然可以改为(?:and|or),但还是不方便。
Perl5.10引入了正则表达式命名捕捉的概念。现在捕捉的结果会进入一个特殊的哈希%+,其中的键就是在捕捉时候使用的特殊标签,其中的值就是被捕捉的串。为捕捉串加标签的方法是使用(?<LABEL>PATTERN)这样的写法,而LABEL可以自行命名。
use 5.010;
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
一旦使用了捕捉标签,就可以随意移动位置并加入更多的捕获括号,不会因为括号的次序变化导致麻烦。
use 5.010;
my $names = 'Fred or Barney';
if($names =~ m/((?<name1>\w+)) (?:and|or) (?<name2>\w+)){
say "I saw $+{name1} and $+{name2}";}
批注:在使用捕捉标签之后,也给反向引用带来了更新的必要。之前我们使用\1或者g{1}这样的写法,现在我们可以使用\g{label}这样的写法。另外一种表示\k<lable>=\g{label}。
use 5.010;
my $names = 'Fred Flinstone and Wilma Flinstone';
if($names =~ m/(?<last_name>\w+) and \w+ \g{last_name}/){
say "I saw $+{last_name}";} (5)自动匹配变量
自动匹配变量有可能是空字符串,它们的有效范围也与标号的匹配变量相同。一般情况下,它们的值会一直持续到下一次模式匹配成功之前。
自动匹配变量会拖慢其它正则表达式的运行速度,所以一般很少使用它们。
$&:字符串里实际匹配模式的部分会自动存进$&里。