gpt4 book ai didi

regex - Perl 正则表达式引擎错误?

转载 作者:行者123 更新时间:2023-12-01 09:47:08 25 4
gpt4 key购买 nike

我一直在尝试编写一个正则表达式来验证文件以确保它遵循特定格式。该文件应该有一个 version(); 行,然后是一个或多个 element(); block 。

这是一个有效文件的示例:

version(1.0);

element
(
);

element
(
);

element
(
);

作为测试,我创建了以下 Perl 示例:

use strict;
use warnings;

my $text = <<'END_TEXT';
version(1.0);

element
(
);

garbage <--- THIS SHOULD NOT MATCH!

element
(
);

element
(
);

END_TEXT

my $rx_defs = qr{(?(DEFINE)
(?<valid_text>
\A\s*(?&version)\s*
(?: (?&element) \s* )+
\s*\Z
)
(?<version>
version\(.+?\);
)
(?<element>
element\s*
(?&element_body);
)
(?<element_body>
\( (?: [^()]++ | (?&element_body) )* \)
)
)}xms;

if ($text =~ m/(?&valid_text)$rx_defs/) {
print "match";
}

如您所见,文本中有一行“垃圾”应该使其无效,但出于某种原因,Perl 似乎仍然认为该文本有效!当我运行这段代码时,它会产生输出:

match

我花了几个小时试图找出我的正则表达式有什么问题,但我就是没发现。我什至使用 online regular expression tester 测试了确切的正则表达式根据测试,我的正则表达式应该可以正常工作! (如果你想看到它在格式有效时确实匹配正确,请尝试删除“垃圾”行。)

这让我一整天都被难住了,我想知道 Perl 正则表达式引擎本身是否存在错误。有人可以告诉我为什么这在不应该匹配的情况下匹配吗?

我正在使用 perl v5.20.1

最佳答案

来自 http://www.pcre.org/current/doc/html/pcre2compat.html 的 PCRE 文档:

  1. Subroutine calls (whether recursive or not) were treated as atomic groups up to PCRE2 release 10.23, but from release 10.30 this changed, and backtracking into subroutine calls is now supported, as in Perl.

regex101 使用 PHP 运行 PCRE。根据http://php.net/manual/en/pcre.installation.php ,PHP 只支持 PCRE1(8.x 分支)。因此 regex101 不支持回溯到子例程调用。

...这正是这里发生的事情:

  • 我们进入 (?&valid_text>) 并尝试匹配 \A\s*(?&version)\s*
  • \A(字符串开头)和 \s*(可选空格)很简单
  • (?&version) 执行 version\(.+?\);
  • 这与输入的以下部分匹配:

    version();

    element
    (
    );

    version( 按字面匹配。下一个字符 ).+? 消耗(至少需要一个字符匹配)。然后 .+? 慢慢地消耗越来越多的字符(它是非贪婪的),直到到达 );。第一次发生这种情况是在使用 之后;元素(,所以我们现在就到此为止。

  • (?&version) 调用返回
  • 我们消耗任何后续空白
  • 下一部分是(?: (?&element)\s* )+,即一个或多个元素,每个元素后跟可选的空格
  • (?&element) 执行 element\s*,即它必须以 element
  • 开头
  • 我们当前在输入中的位置是garbage ...,所以失败了

此时正则表达式引擎尝试回溯。在 PCRE < 10.30 中,唯一可以回溯的部分是 \s*(即“可选空白”位),但匹配较少的空白字符也不会导致成功匹配,因此整个事情很快就会失败。

但是,在 Perl 中我们可以回溯到子例程调用:我们重新输入 (?&version) 并让 .+? 匹配更多字符(直到下一次出现); 找到),然后重试 (?&element)。这最终让 (?&version) 消耗了 garbage 和后面的 element,这反过来又让整个正则表达式成功。

Can somebody please tell me why this is matching when it shouldn't?

我不明白为什么你认为它不应该匹配。 :-)

它在 PHP 中不匹配的唯一原因是它使用的旧 PCRE 版本存在限制。

关于regex - Perl 正则表达式引擎错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46353415/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com