Perl正则表达式(regex)在我设为可选时失败

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl正则表达式(regex)在我设为可选时失败相关的知识,希望对你有一定的参考价值。

我正在Perl 5.22上运行以下代码段:

  DB<41> x "up 34 days, 22:04 and more" =~ m/.*?(?:(\d+) days).*$/
0  34

以上代码按预期工作,并从“ 34天”中抽出了34天。

我的问题是,通过添加一个使捕获组成为可选的?在它的末尾是这样的:

  DB<4> x "up 34 days, 22:04 and more" =~ m/.*?(?:(\d+) days)?.*$/
0  undef

为什么它不再匹配34?我已经在网上搜索过,但是找不到与我的匹配的任何问题(如果您有一个解释它的链接,那就太好了)。

感谢您的宝贵时间。

答案

为什么它不再匹配34?

因为.*? in

"up 34 days, 22:04 and more" =~ m/.*?(?:(\d+) days)?.*$/

现在可以一直匹配到字符串的末尾,因为后面的内容可能匹配零次。

另一答案

正则表达式始终从左到右工作;量词总是首先尝试尽可能多地匹配,或者在不贪心时尽可能少匹配(例如.*?)。当他们达到不可比拟的状态时,只有这样,他们才会备份并尝试进行新的匹配(回溯)。正则表达式的关键在于正则表达式引擎将首先尝试的方法。

.*?首先将尝试在字符串的开头匹配空字符串,因为这是它可以匹配的最少字符。对于第一个正则表达式,这不会导致成功的整体匹配,因此最终回溯直到.*?匹配“ up”,以便随后的组可以匹配“ 34天”。但是,如果将以下组设为可选,则首先尝试将.*?的初始模式与空字符串匹配,然后将(?:(\d+) days)?与空字符串匹配(因为它不能与数字匹配,后跟“ days”)特定位置,但可以匹配空字符串),然后是.*,匹配其余字符串,然后是字符串末尾;成功的比赛。

Regexp::Debuggerhttps://regex101.com/都可以很好地可视化行为(只是要注意PCRE与Perl regex不完全相同)。

另一答案

由于.*?(?:(\d+) days)?都匹配空字符串,然后.*$然后匹配任何其他字符串,即整个输入字符串。

如果您检查以下内容

use strict;
use warnings;

my $s = "up 34 days, 22:04 and more";

if ($s =~ m/.*?(?:(\d+) days)(.*)$/) 
  print("first:\n  $1=\"$1\"\n  \$2=\"$2\"\n");

if ($s =~ m/.*?(?:(\d+) days)?(.*)$/) 
  print("second:\n  \$1=\"$1\"\n  \$2=\"$2\"\n");

您会得到

first:
  34="34"
  $2=", 22:04 and more"
second:
  $1=""
  $2="up 34 days, 22:04 and more"

作为输出(以及有关$1的未定义警告,您可以在此处忽略这是说明。

以上是关于Perl正则表达式(regex)在我设为可选时失败的主要内容,如果未能解决你的问题,请参考以下文章

regex格式的名称

将“NSManaged public var”设为可选布尔值

使用 View Controller 作为辅助视图的委托失败,在展开可选时意外发现 nil

Core Data codegen 如何决定是不是将属性设为可选?

使用 Pydantic 将每个字段设为可选

PERL:用破折号读取社会保障号的正则表达式