我理解将?:
放在正则表达式的括号开头之内将阻止它创建一个应该更快的反向引用。我的问题是,为什么这样做?速度是否足够明显以保证这一考虑?在什么情况下它会如此重要,以至于每次你不打算使用它时都需要仔细跳过反向引用。另一个缺点是它使正则表达式更难以阅读,编辑和更新(如果你最后想要使用反向引用)。
总而言之,为什么不打算不创建反向引用呢?
答案 0 :(得分:13)
我认为你混淆了像\1
这样的反向引用和捕获群组(...)
。
反向引用通过使语言非常规来阻止各种优化。
捕获组使正则表达式引擎能够更多地记住组的开始和结束位置,但不如后向引用那么糟糕。
http://www.regular-expressions.info/brackets.html详细解释了捕获组和对它们的引用。
编辑:
在使正则表达式非常规的反向引用上,请考虑以下与lua注释匹配的正则表达式:
/^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/
因此--[[...]]
是评论,--[=[...]=]
是评论,--[==[...]==]
是评论。
您可以通过在方括号之间添加额外的等号来嵌套注释。
这不能与严格的regular language匹配,所以一个简单的有限状态机无法在O(n)时间内处理它 - 你需要一个计数器。
Perl 5正则表达式可以使用反向引用来处理它。但只要您需要非常规模式匹配,您的正则表达式库就必须放弃简单的状态机方法,并使用更复杂,效率更低的代码。
答案 1 :(得分:5)
你是对的,表现并不是避免捕捉群体的唯一理由 - 事实上,这甚至不是最重要的原因。
另一个缺点是它使正则表达式更难阅读,编辑和更新(如果你最后想要使用反向引用)。
我反过来看:如果你习惯性地使用非捕捉群体,那么当你做选择捕捉某些东西时,更容易跟踪群组号码。同样,如果你正在使用命名组(假设你的正则表达式支持它们),你应该总是使用命名组,并且总是引用给它们(在后面的引用中)或替换字符串)按名称而不是数字。遵循这些规则将至少部分地抵消非捕获组的可读性惩罚。
是的,PITA必须以这种方式混乱你的正则表达式,编写/维护正则表达式实现的人都知道它。在.NET中,您可以设置ExplicitCapture
选项,其中所有“裸”括号都被视为非捕获组,并且只有命名组捕获。在Perl 6中,括号(带或不带名称)总是捕获,方括号用于非捕获组。其他口味最终可能会效仿,但与此同时我们必须依赖良好的习惯。