【问题标题】:Perl - backreference not available when capture group is followed by?Perl - 当捕获组后跟时反向引用不可用?
【发布时间】:2013-11-23 16:08:16
【问题描述】:

当捕获组后跟问号时,反向引用似乎不可用

my $test = "this is a very long day indeed";

if ($test =~ m/^this.+(very).+(indeed)?/) {
  print "It matched the regex.\n";
  print "$1 :: $2\n";
}

打印出来

It matched the first test.
very :: 

这是正常行为吗?我在任何文档中都找不到提及它。我正在尝试匹配日志文件中可能存在或不存在第二个捕获组的行。

【问题讨论】:

标签: regex perl backreference


【解决方案1】:

这不是反向引用问题。您最后一组中的字符与 .+ 匹配,但与您的可选捕获组不匹配,因此最后一组匹配空字符串。

问题是你使用了一个贪婪的量词来匹配之前所有可能的字符。由于您的最后一组是可选的,.+ 匹配所有直到行尾,正则表达式引擎不需要回溯以匹配您的字符串(并且不需要找到“确实”)。

解决问题的一个简单方法是使用惰性量词和结束锚点强制走到行尾(因为惰性量词会尽快停止):

m/^this.+(very).+?(indeed)?$/

注意:如果“确实”不是字符串的最后一个字符,则必须在 $ 之前添加 .*

【讨论】:

  • 太棒了!我实际上正在解析一个 exim 日志文件 - 正则表达式现在很好用 - /${timeStamp}.+ cwd=(\/home[0-9]{0,2}\/.+) [0-9]+ args.+?(?: -f ([^@\s]+@[^@\s]+))?$/
  • @user2210814:为你高兴。但是当你有这样的任务时,如果你给出“真实的”(带有错误值)示例字符串和你正在尝试做的事情,你将获得更合适的答案。如果你提供一个更具体的例子,我很确定我会给你一个更好的回应。
【解决方案2】:

这是关于贪婪的附加说明,这是您的问题(Casimir 已回答)。

意识到正则表达式引擎默认情况下会消耗它所能做的一切,直到它找到满足当前求值子表达式右侧的子表达式为止。

任何时候你想使用带有 DOT 元字符的 .+ 贪婪量词都应该引发红旗三思而后行。如果可以的话,它会吹过你可能打算做的事情。

因此,请尝试将其替换为更具体的内容,但不会超过您的预期目标。

稍微修改您的示例正则表达式会显示这是如何发生的。

 my $test = "this is a very long day indeed, very long.";

 if ($test =~ m/

      ^
      ( this )               # (1)
      ( .+ )                 # (2)
      ( very )               # (3)
      ( .+ )                 # (4)
      ( indeed )?            # (5)

 /x) {
   print "All  = '$&'\n";
   print "grp1 = '$1'\n";
   print "grp1 = '$2'\n";
   print "grp1 = '$3'\n";
   print "grp1 = '$4'\n";
 }

 # Output >>
 # 
 # All  = 'this is a very long day indeed, very long.'
 # grp1 = 'this'
 # grp1 = ' is a very long day indeed, '
 # grp1 = 'very'
 # grp1 = ' long.'
 # 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    相关资源
    最近更新 更多