【问题标题】:Regex efficency正则表达式效率
【发布时间】:2020-05-11 09:43:20
【问题描述】:

给定这个字符串

xxv jkxxxxxxxxxxxxxxx xxyu xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxAp oSxx
xxAp oSxxxxxxxxxxxxxxxxxxxxxj xxxxxxxxxuixxxxxxxxxxx axxxxxxxxxxxxxxxxxx

还有这个正则表达式

^[^\r\n]*Ap oS[^\r\n]*

我希望在任何地方匹配任何包含Ap oS 的行,如here 所示,并且它可以做到这一点。

现在,通过查看debugger,可以看到第一个匹配需要 16 步,第二个需要 80 步,因为回溯,如果我理解正确的话。

我的问题是,如何编写这个正则表达式来减少步数?

我想用(?!Ap oS)* 替换第一个[^\r\n]* 以匹配不是Ap oS 的所有内容,直到找到Ap oS,但我不确定我是否理解概念或语法错误,或者两者都有。

感谢任何帮助

【问题讨论】:

    标签: regex performance pcre


    【解决方案1】:

    你想在这里申请unroll-the-loop technique

    ^[^A\r\n]*(?:A(?!p oS)[^A\r\n]*)*Ap oS[^\r\n]*
    

    regex demo

    详情

    • ^ - 字符串开头
    • [^A\r\n]* - CR、LF 和 A 以外的 0+ 个字符
    • (?:A(?!p oS)[^A\r\n]*)* - 0 次或多次出现 A 后不跟 p oS,然后是 0+ CR、LF 和 A 以外的字符
    • Ap oS - 你的字符串
    • [^\r\n]* - CR 和 LF 以外的 0 个或多个字符。

    【讨论】:

    • 对此进行详细说明,请参阅this 并添加一些不匹配的行。这说2 matches, 50 steps。但是,查看debugger 会显示 489 个步骤。看起来这种技术将采取更多步骤,匹配行和这些行的结构越少。为了改进这些非匹配行所采取的步骤,我实现了 20% 的改进here。但是,第 4 行仍然存在问题。有什么办法可以进一步改进?
    【解决方案2】:

    您可以使用以下模式之一以更简单有效的方式应用 展开循环 技术:

    ^(?:[^A\r\n]*A)+?p oS.*
    

    demo

    (请注意,pcre 使量词 *[^A\r\n]*A 中自动具有所有格,因为 A 遵循重复的字符类,从它被排除在外。换句话说,替换此子模式周围的非捕获组使用原子组或明确地使量词所有格是无用的。)

    或者如果您希望文字部分完全显示:

    ^[^A\r\n]*+(?>A[^A\r\n]*)*?Ap oS.*
    

    demo

    您不需要使用前瞻,因为这是不情愿量词在这里所做的(它在每次组迭代后测试下一个子模式)。


    请注意,由于您正在寻找包含文字字符串的行,并且如果您的数据来自文件,那么在许多编程语言中,简单地逐行读取文件并使用基本字符串过滤它们可能会更有趣功能。


    根据 pcre 中的默认换行符序列和字符串中使用的换行符,模式末尾的.* 可以匹配回车符。为避免这种行为,您可以明确设置换行符序列,以 (*CRLF) 开始您的模式。


    减少模式的步骤数是提高模式效率的一种方法,但请注意不要仅仅为此目的构建太长或太复杂的模式,因为它也可能适得其反。

    【讨论】:

    • 感谢@Casimir 非常有帮助。最后一个问题,在您的最后一个demo 中,当您查看debugger 时,它会显示2 matches, 47 steps (~0ms) hoevwer,它显示了339 个步骤。这些数字代表什么?应该将哪一个用作基准?
    • @fionpo:没有一个,如果你想对一个模式进行基准测试,用几个真实的字符串测试它并多次计时。请注意,调试器不考虑 pcre 优化。
    猜你喜欢
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 2020-08-11
    • 2016-04-23
    • 2022-12-05
    • 2017-07-16
    相关资源
    最近更新 更多