两种模式的区别在于潜在的效率。
The (exp1 | exp2)*
Pattern 包含一个自动禁用某些内部正则表达式匹配优化的替代。此外,此正则表达式尝试匹配字符串中每个位置的模式。
The (exp1 * (exp2 exp1*)*)
表达式是按照.到展开循环 http://www.softec.lu/site/RegularExpressions/UnrollingTheLoop原则:
该优化技术用于优化表单的重复交替(expr1|expr2|...)*
。这些表达式并不罕见,并且在交替中使用另一个重复也可能导致超线性匹配。超线性匹配源自undertermistic表达式(a*)*
.
展开循环技术基于这样的假设:在大多数情况下,您通过重复的交替知道哪种情况应该是最常见的,哪种情况是例外的。我们将第一个称为正常情况,第二个称为特殊情况。展开循环技术的一般语法可以写为:
normal* ( special normal* )*
So, the exp1
在你的例子中是normal那部分是最常见的, and exp2
预计频率会降低。在这种情况下,展开模式的效率实际上比其他正则表达式高得多,因为normal*
部分将抓取整个输入块,无需停止和检查each地点。
我们看一个简单的"([^"\\]|\\.)*"正则表达式测试"some text here" https://regex101.com/r/zH1mR0/1:涉及 35 个步骤:
将其展开为"[^"\\]*(\\.[^"\\]*)*" https://regex101.com/r/zH1mR0/2由于回溯少得多,因此增加了 6 个步骤。
NOTEregex101.com 的步骤数并不直接意味着一个正则表达式比另一个更有效,但是,调试表显示了回溯发生的位置,以及回溯is资源消耗。
然后我们用 JS benchmark.js 来测试模式效率:
var suite = new Benchmark.Suite();
Benchmark = window.Benchmark;
suite
.add('Regular RegExp test', function() {
'"some text here"'.match(/"([^"\\]|\\.)*"/);
})
.add('Unrolled RegExp test', function() {
'"some text here"'.match(/"[^"\\]*(\\.[^"\\]*)*"/);
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run({ 'async': true });
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/platform/1.3.1/platform.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/2.1.0/benchmark.js"></script>
Results:
Regular RegExp test x 9,295,393 ops/sec ±0.69% (64 runs sampled)
Unrolled RegExp test x 12,176,227 ops/sec ±1.17% (64 runs sampled)
Fastest is Unrolled RegExp test
另外,自从展开循环概念不是特定于语言的,这里有一个在线PHP测试 https://ideone.com/JaQQlA(常规模式产生~0.45,并展开一个屈服~0.22结果)。
另请参阅展开循环,何时使用 https://stackoverflow.com/questions/38018210/unroll-loop-when-to-use/38018490#38018490.