"[abc]"和"(a|b|c)"的区别

4
对于 PCRE 正则表达式,[abc] 和 (a|b|c) 有什么区别?

4
相关问题使用选择分支或字符类匹配单个字符?有一些有趣的回答。 - stema
3个回答

10
您的问题中的模式匹配相同的文本。在实现方面,它们对应于不同的自动机和副作用(即,它们是否捕获子字符串)。
在下面的评论中,Garrett Albright 指出了微妙的区别。虽然(.| \n)匹配任何字符,但[.\n]只匹配文字点或换行符。尽管在字符类内部点不再是特殊字符,但其他字符(如-^])以及序列(如[:lower:])在字符类内部具有特殊含义。需要注意保留一个上下文中的特殊语义到另一个上下文中,但有时这是不可能的,比如在\1作为写在字符类外部的$1的过时方式的情况下。在字符类内部,\1始终匹配字符SOH。

字符类([...])用于匹配一组字符中的一个,而替代项(x|y)允许更一般长度不同的选择。如果您记住这些设计原则,您将倾向于看到更好的性能。正则表达式实现将源代码(例如/[abc]/)转换为有限状态自动机,通常是NFAs。我们所谓的正则表达式引擎更或多或少是协助执行这些目标状态机的簿记员。足够聪明的正则表达式编译器将为等效的正则表达式生成相同的机器码,但由于lurking exponential complexity的存在,在一般情况下这很困难和昂贵。

如果想了解正则表达式背后的理论,可以阅读Mark Dominus的“How Regexes Work”。如果想深入学习,可以考虑Peter Linz的An Introduction to Formal Languages and Automata


你什么时候会使用其中一个而不是另一个?“它们对应于不同的自动机和子字符串捕获”是什么意思?谢谢。 - user1032531
如果a、b和c只是字母,那当然是这样的(我认为这就是意思)。如果它们代表单词,那么语义显然完全不同。 - kratenko
我发现有时方括号选项对于像\n\r这样的特殊字符似乎无法正常工作。例如,要捕获包括换行符在内的FOO和BAR之间的所有文本,/FOO((.|\n)+)BAR/有效,而/FOO([.\n]+)BAR/则无效。虽然这可能是实现特定的,但我发现了其他类似的差异,但我无法立即回忆起来。无论如何,作为一个规则,我会首先尝试使用[ab],因为它更易读,如果事情似乎不起作用,那么再尝试(a|b) - Garrett Albright
@Garrett 说得好。我假设所有非特殊字符。请看更新。 - Greg Bacon
(. | \n)和[.\n]是完全不同的。后者只匹配点字符和\n。如果您想要“dotall”,也可以使用\p{Any}。 - dark100

1
(阅读格雷格的回答后):它们是否应该被不同地评估取决于您输入到程序中的内容。根据您想要检查什么来选择。您是想检查有效字符池,还是想检查值。-有时可能看起来相同,但背后的意图可能不同。然后选择反映您意图的选项。

0
使用方括号的表达式在启用JIT编译时,使用PCRE会更快。它只是在位集中检查一个位,而另一个则为每个备选项重新读取字符。我正在考虑一种优化方法,可以检测这种情况,因为许多人不知道字符类可以用在方括号内,他们使用([a-z]|\s)+而不是[a-z\s]+。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接