首页 > 解决方案 > 正则表达式:PCRE 原子组不起作用

问题描述

在我的 PCRE 正则表达式中,我使用了一个原子组来减少回溯。

<\/?\s*\b(?>a(?:bbr|cronym|ddress|pplet|r(?:ea|ticle)|side|udio)?|b(?:ase|asefont|d[io]|ig|lockquote|ody|r|utton)?|c(?:anvas|aption|enter|ite|ode|ol(?:group)?)|d(?:ata(?:list)?|[dlt]|el|etails|fn|ialog|i[rv])|em(?:bed)?|f(?:i(?:eldset|g(?:caption|ure))|o(?:nt|oter|rm)|rame(?:set)?)|h(?:[1-6r]|ead(?:er)?|tml)|i(?:frame|mg|nput|ns)?|kbd|l(?:abel|egend|i(?:nk)?)|m(?:a(?:in|p|rk)|et(?:a|er))|n(?:av|o(?:frames|script))|o(?:bject|l|pt(?:group|ion)|utput)|p(?:aram|icture|re|rogress)?|q|r[pt]|ruby|s|s(?:amp|ection|elect|mall|ource|pan|trike|trong|tyle|ub|ummary|up|vg)|t(?:able|body|[dhrt]|emplate|extarea|foot|head|ime|itle|rack)|ul?|v(?:ar|ideo)|wbr)\b

正则表达式101

但是在示例调试中,我看到f检查结束后,它会进一步用于其他选项。我试图在f检查失败后停止它,所以它不会检查表达式的其余部分。怎么了?

标签: regexpcre

解决方案


我将假设您在这里使用正则表达式知道您在做什么,因为可能有一个论点是 PCRE 不是以“树”状方式实现这种匹配的最佳方法。但我对此并不大惊小怪。

使用条件的想法不错,但它以条件本身的形式增加了额外的步骤。此外,每个条件只能在两个方向上分支。

PCRE 有一个称为“回溯控制动词”的功能,它可以让你精确地做你想做的事。他们有不同程度的控制,在这种情况下我建议的是最强的:

<\/?\s*\b(?>a(?:bbr|cronym|ddress|pplet|r(?:ea|ticle)|side|udio)?|b(?:ase|asefont|d[io]|ig|lockquote|ody|r|utton)?|c(?:anvas|aption|enter|ite|ode|ol(?:group)?)|d(?:ata(?:list)?|[dlt]|el|etails|fn|ialog|i[rv])|em(?:bed)?|f(*COMMIT)(?:i(?:eldset|g(?:caption|ure))|o(?:nt|oter|rm)|rame(?:set)?)|h(?:[1-6r]|ead(?:er)?|tml)|i(?:frame|mg|nput|ns)?|kbd|l(?:abel|egend|i(?:nk)?)|m(?:a(?:in|p|rk)|et(?:a|er))|n(?:av|o(?:frames|script))|o(?:bject|l|pt(?:group|ion)|utput)|p(?:aram|icture|re|rogress)?|q|r[pt]|ruby|s|s(?:amp|ection|elect|mall|ource|pan|trike|trong|tyle|ub|ummary|up|vg)|t(?:able|body|[dhrt]|emplate|extarea|foot|head|ime|itle|rack)|ul?|v(?:ar|ideo)|wbr)\b

https://regex101.com/r/p572K8/2

只需在“f”分支后添加一个(*COMMIT)动词,就可以将在这种情况下查找失败所需的步骤减少一半。

(*COMMIT)告诉引擎在那个时候提交匹配。</如果找不到匹配项,它甚至不会重新尝试重新开始匹配。

要完全优化表达式,您必须(*COMMIT)在分支发生后的每个点添加。

您可以做的另一件事是尝试重新排序您的备选方案,以便优先考虑最常见的备选方案。这可能是您优化过程中需要考虑的其他因素。


推荐阅读