考虑以下perl脚本:
#!/usr/bin/perl
my $str = 'not-found=1,total-found=63,ignored=2';
print "1. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
print "2. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
print "3. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
print "4. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
print "Bye!\n";
运行此后的输出是:
1. matched using regex
3. matched using regex
Bye!
相同的正则表达式匹配一次,之后不匹配。任何想法为什么备用尝试匹配同一个字符串与相同的正则表达式在perl中失败?
谢谢!
答案 0 :(得分:4)
以下是长解释为什么您的代码不起作用。
/g
修饰符将正则表达式的行为更改为“全局匹配”。这将匹配字符串中所有出现的模式。但是,如何完成此匹配取决于 context 。 Perl中的两个(主要)上下文是列表上下文(复数)和标量上下文(单数)。
在列表上下文中,全局正则表达式匹配返回所有匹配的子字符串的列表,或所有匹配的捕获的平面列表:
my $_ = "foobaa";
my $regex = qr/[aeiou]/;
my @matches = /$regex/g; # match all vowels
say "@matches"; # "o o a a"
在标量上下文中,匹配似乎返回perl布尔值,描述正则表达式是否匹配:
my $match = /$regex/g;
say $match; # "1" (on failure: the empty string)
然而,正则表达式变成了迭代器。每次执行正则表达式匹配时,正则表达式从字符串中的当前位置开始,并尝试匹配。如果匹配,则返回true。如果匹配失败,那么
因为重置了字符串中的位置,所以下一场比赛将再次成功。
my $match;
say $match while $match = /$regex/g;
say "The match returned false, or the while loop would have go on forever";
say "But we can match again" if /$regex/g;
第二个效果 - 重置位置 - 可以使用额外的/c
标记取消。
可以使用pos
函数访问字符串中的位置:pos($string)
返回当前位置,可以设置为pos($string) = 0
。
正则表达式也可以在当前位置使用\G
断言锚定,就像^
在字符串的开头处锚定正则表达式一样。
此m//gc
- 样式匹配可以轻松编写标记生成器:
my @tokens;
my $_ = "1, abc, 2 ";
TOKEN: while(pos($_) < length($_)) {
/\G\s+/gc and next; # skip whitespace
# if one of the following matches fails, the next token is tried
if (/\G(\d+)/gc) { push @tokens, [NUM => $1]}
elsif (/\G,/gc ) { push @tokens, ['COMMA' ]}
elsif (/\G(\w+)/gc) { push @tokens, [STR => $1]}
else { last TOKEN } # break the loop only if nothing matched at this position.
}
say "[@$_]" for @tokens;
输出:
[NUM 1]
[COMMA]
[STR abc]
[COMMA]
[NUM 2]
答案 1 :(得分:3)
摆脱m
和g
作为你的正则表达式的修饰符,它们没有做你想要的。
print "1. matched using regex\n" if ($str =~ /total-found=(\d+)/);
print "2. matched using regex\n" if ($str =~ /total-found=(\d+)/);
print "3. matched using regex\n" if ($str =~ /total-found=(\d+)/);
print "4. matched using regex\n" if ($str =~ /total-found=(\d+)/);
具体而言,m
在此上下文中是可选的m/foo/
与/foo/
完全相同。真正的问题是g
会在这种情况下做一些你不想要的事情。有关详细信息,请参阅perlretut。
答案 2 :(得分:1)
my $str = 'not-found=1,total-found=63,ignored=2';
print "1. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
匹配total-found=63
和pos($str)
,以便下次匹配尝试设置为偏移26。
print "2. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
匹配nothing
,因此pos($str)
重置为偏移0。
这就是为什么
print "3. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
再次匹配total-found=63
和pos($str)
,下次匹配尝试再次设置为偏移26,这就是为什么
print "4. matched using regex\n" if ($str =~ m/total-found=(\d+)/g);
再次失败,就像第二个一样,将pos($str)
重新设置为偏移0。
print "Bye!\n";