微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

正则表达式 – Perl正则表达式引擎错误?

我一直在尝试编写一个正则表达式来验证文件,以确保它遵循特定的格式.该文件应该有一个版本();行后面跟一个或多个元素();块.

以下是有效文件的示例:

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

解决方法

非贪婪的比赛一旦满足就不会停止.它试图尽快继续.如果正则表达式的其余部分无法匹配,则仍会发生回溯 – 但对于非贪婪的量词,回溯意味着匹配更多.

避免这种情况的一种可能性在于回溯控制.例如,您可能希望在版本最初匹配后禁止回溯.我们可以通过(?> …)构造来做到这一点.这与外部模式独​​立地匹配包含的模式.如果模式的其余部分失败,则回溯将不会继续进入包含的模式,但会跳过整个包含的模式.描述这个有点困难,详情请见perldoc perlre.

添加到量词(例如,?,*)具有与(?> …)类似的效果.在有效的正则表达式中,优选这些无回溯量词和(?> …)组是非常可取的.

具体来说,替换

(?<valid_text>
    \A\s*(?&version)\s*
    (?: (?&element) \s* )+
    \s*\Z
)

(?<valid_text>
    \A\s*(?>(?&version))\s*
    (?: (?&element) \s* )++
    \s*\Z
)

作为另一种选择,您可以使用(* PRUNE)回溯控制动词.遇到PRUNE命令后,不会发生超过该点的回溯.这使得匹配到目前为止所选择的替代方案.

(?<valid_text>
    \A\s*(?&version)\s* (*PRUNE)
    (?: (?&element) \s* )+
    \s*\Z
)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐