在perl中使用正则表达式匹配的奇怪问题,备用尝试匹配

ami*_*rav 5 regex perl

请考虑以下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";
Run Code Online (Sandbox Code Playgroud)

运行此后的输出是:

1. matched using regex
3. matched using regex
Bye!
Run Code Online (Sandbox Code Playgroud)

相同的正则表达式匹配一次,之后不匹配.任何想法为什么备用尝试匹配同一个字符串与相同的正则表达式在perl中失败?

谢谢!

amo*_*mon 5

这是为什么您的代码不起作用的详细解释

/g修改改变了正则表达式为“全球配套”的行为。这将匹配字符串中所有出现的模式。但是,如何进行匹配取决于上下文。Perl 中的两个(主要)上下文是列表上下文(复数)和标量上下文(单数)。

list context 中,全局正则表达式匹配返回所有匹配子字符串的列表,或所有匹配捕获的平面列表:

my $_ = "foobaa";
my $regex = qr/[aeiou]/;

my @matches = /$regex/g; # match all vowels
say "@matches"; # "o o a a"
Run Code Online (Sandbox Code Playgroud)

标量上下文中,匹配似乎返回一个 perl 布尔值,描述正则表达式是否匹配:

my $match = /$regex/g;
say $match; # "1" (on failure: the empty string)
Run Code Online (Sandbox Code Playgroud)

然而,正则表达式变成了迭代器。每次执行正则表达式匹配时,正则表达式从字符串中的当前位置开始,并尝试匹配。如果匹配,则返回 true。如果匹配失败,则

  • 匹配返回false,并且
  • 字符串中的当前位置设置为开头。

因为字符串中的位置被重置,下一次匹配将再次成功。

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;
Run Code Online (Sandbox Code Playgroud)

第二个效果——重置位置——可以用附加/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;
Run Code Online (Sandbox Code Playgroud)

输出:

[NUM 1]
[COMMA]
[STR abc]
[COMMA]
[NUM 2]
Run Code Online (Sandbox Code Playgroud)


Ryl*_*ley 3

摆脱mg作为正则表达式的修饰符,它们没有做你想要的事情。

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+)/);
Run Code Online (Sandbox Code Playgroud)

具体来说,m在这种情况下, 是可选的m/foo/与 完全相同/foo/。真正的问题是g在这种情况下做了很多你不想要的事情。详细信息请参见perlretut 。

  • m 可以留在图片中。这是多余的,但不会造成伤害。括号(全部)可以去掉。 (2认同)