Regex 原子团透明度
以这个正则表达式为例Regex 原子团透明度,regex,pcre,backtracking,Regex,Pcre,Backtracking,以这个正则表达式为例 a*b (?>a*)b 如果aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 这需要调试器中的67步骤失败 现在考虑这个正则表达式。< /P> a*b (?>a*)b 如果aaaaaaaaaaa
a*b
(?>a*)b
如果aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
这需要调试器中的67
步骤失败
现在考虑这个正则表达式。< /P>
a*b
(?>a*)b
如果aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
这需要调试器中的133
步骤失败
最后,这个正则表达式:
a*+b (a variant of atomic group)
如果aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
这需要调试器中的67
步骤失败
当我检查基准原子组(?>a*)时,b
执行179%
更快
现在原子组禁用回溯。所以在比赛中表现不错
但为什么要多走几步呢?有人能解释一下吗
为什么在两个原子群(?>a*)b
和a*+b
之间存在步进差异
它们的工作方式不同吗?那么什么是回溯呢?
引擎出现默认贪婪的量词。贪婪修饰符根据需求匹配所有可能的和回溯,允许高效匹配
引用人:
贪婪的量词首先尽可能匹配。因此,*
匹配整个字符串。然后匹配器尝试匹配下面的f
,但没有剩余字符。因此它“回溯”,使贪婪的量词少匹配一个东西(使字符串末尾的“o”不匹配)。这仍然与正则表达式中的f
不匹配,因此它又“回溯”了一步,使贪婪的量词再次匹配更少的东西(使字符串末尾的“oo”不匹配)。这仍然与正则表达式中的f
不匹配,因此它又返回了一个步骤(使字符串末尾的“foo”不匹配)。现在,匹配器最终匹配正则表达式中的f
,并且o
和下一个o
也被匹配。成功![……]
这与a*+b
有什么关系?
在/a*+b/
中:
a
文字字符“a”
*+
零或更多,所有格
b
文本字符“b”
引用人:
所有格量词就像贪婪量词一样,但它不会后退。因此,它从匹配整个字符串开始,不留下任何不匹配的内容。那么它就没有什么东西可以与正则表达式中的f
匹配了。由于所有格量词没有回溯,因此匹配失败
为什么这很重要?
机器无法意识到自己是否在进行有效匹配。请参阅此处以获取一个合适的示例:。在许多场景中,快速编写的正则表达式可能效率不高,并且在部署中很容易出现问题
那么什么是原子团?
在原子组内的模式完成匹配后,它永远不会放弃。研究这个例子:
Pattern: (?>\d\w{2}|12)c
Matching string: 12c
看起来完全合法,但此匹配失败。步骤很简单:原子组的第一次交替完全匹配-\d\w{2}
消耗12c
。然后该组完成匹配-现在是指针位置:
Pattern: (?>\d\w{2}|12)c
^
Matching string: 12c
^
这种模式在发展。现在我们尝试匹配c
,但是没有c
。匹配失败,而不是尝试回溯(释放\d\w{2}
并使用12
)
那是个坏主意!我们为什么要阻止回溯,单面体?
现在假设我们正在使用JSON对象进行操作。这个文件不小。从最后开始回溯是个坏主意
"2597401":[{"jobID":"2597401",
"account":"TG-CCR120014",
"user":"charngda",
"pkgT":{"pgi/7.2- 5":{"libA":["libpgc.so"],
"flavor":["default"]}},
"startEpoch":"1338497979",
"runTime":"1022",
"execType":"user:binary",
"exec":"ft.D.64",
"numNodes":"4",
"sha1":"5a79879235aa31b6a46e73b43879428e2a175db5",
"execEpoch":1336766742,
"execModify":"Fri May 11 15:05:42 2012",
"startTime":"Thu May 31 15:59:39 2012",
"numCores":"64",
"sizeT":{"bss":"1881400168","text":"239574","data":"22504"}},
{"jobID":"2597401",
"account":"TG-CCR120014",
"user":"charngda",
"pkgT":{"pgi/7.2-5":{"libA":["libpgc.so"],
"flavor":["default"]}},
"startEpoch":"1338497946",
"runTime":"33" "execType":"user:binary",
"exec":"cg.C.64",
"numNodes":"4",
"sha1":"caf415e011e28b7e4e5b050fb61cbf71a62a9789",
"execEpoch":1336766735,
"execModify":"Fri May 11 15:05:35 2012",
"startTime":"Thu May 31 15:59:06 2012",
"numCores":"64",
"sizeT":{"bss":"29630984","text":"225749","data":"20360"}},
{"jobID":"2597401",
"account":"TG-CCR120014",
"user":"charngda",
"pkgT":{"pgi/7.2-5": {"libA":["libpgc.so"],
"flavor":["default"]}},
"startEpoch":"1338500447",
"runTime":"145",
"execType":"user:binary",
"exec":"mg.D.64",
"numNodes":"4",
"sha1":"173de32e1514ad097b1c051ec49c4eb240f2001f",
"execEpoch":1336766756,
"execModify":"Fri May 11 15:05:56 2012",
"startTime":"Thu May 31 16:40:47 2012",
"numCores":"64",
"sizeT":{"bss":"456954120","text":"426186","data":"22184"}},{"jobID":"2597401",
"account":"TG-CCR120014",
"user":"charngda",
"pkgT":{"pgi/7.2-5":{"libA":["libpgc.so"],
"flavor":["default"]}},
"startEpoch":"1338499002",
"runTime":"1444",
"execType":"user:binary",
"exec":"lu.D.64",
"numNodes":"4",
"sha1":"c6dc16d25c2f23d2a3321d4feed16ab7e10c2cc1",
"execEpoch":1336766748,
"execModify":"Fri May 11 15:05:48 2012",
"startTime":"Thu May 31 16:16:42 2012",
"numCores":"64",
"sizeT":{"bss":"199850984","text":"474218","data":"27064"}}],
啊哦
你明白我的意思了吗P
我会让你们去弄清楚剩下的,试着找出更多关于所有格量词和原子群的信息;我没有在这篇文章里写任何其他东西。这就是JSON的来源,几天前我看到了答案,非常鼓舞人心:
同时阅读
我觉得有点不对劲。。。
我不知道您是如何进行基准测试的,但是a*+b
和(?>a*)b
应该是相同的。引用(我的重点):
基本上,不是写X*+
,而是写(?>X*)
。需要注意的是,量化标记X
和量词都位于原子组内。即使X
是一个组,您仍然需要在其周围放置一个额外的原子组以实现相同的效果(?:a | b)*+
等同于(?>(?:a | b)*)
,但不等同于(?>a | b)*
。后者是一个有效的正则表达式,但当作为更大的正则表达式的一部分使用时,它不会有相同的效果
为了确认上述内容,我在上运行了以下命令:
现在,我绝不是一个PHP专家,所以我不知道这是否是对其中的内容进行基准测试的正确方法,但这是因为它们都具有相同的性能,考虑到任务的简单性,这是一种预期
尽管如此,我还是从上面注意到了几件事:
(?>a)*b
和(?>a*)b
都比另一个正则表达式快179%;以上各项之间的差距均在7%以内
回到实际问题上来
但为什么要多走几步呢?有人能解释一下吗
需要注意的是,步骤的数量并不能直接表示正则表达式的性能。这是一个因素,但不是最终决定因素。有更多的步骤,因为细分在进入组之前有步骤,而在进入组之后
1 / (?> a* ) b/x aaaaaaaaaaaaaaaaaaaa...
^
2 / (?> a* ) b/x aaaaaaaaaaaaaaaaaaaa...
^^^^^^^^
3 / (?> a* ) b/x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
^^
4 / (?> a* ) b/x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
^
5 / (?> a* ) b/x aaaaaaaaaaaaaaaaaaaaa...
^
因为团队的原因,这比3个步骤多了2个步骤
1 / a*+ b /x aaaaaaaaaaaaaaaaaaaa...
^
2 / a*+ b /x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
^^^
3 / a*+ b /x aaaaaaaaaaaaaaaaaaaaa...
^
其中,您可以说a*b
与(?:a*)b
相同,但后者有更多步骤:
1 / (?: a* ) b/x aaaaaaaaaaaaaaaaaaaa...
^
2 / (?: a* ) b/x aaaaaaaaaaaaaaaaaaaa...
^^^^^^^^
3 / (?: a* ) b/x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
^^
4 / (?: a* ) b/x aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
^
5 / (?: a* ) b/x aaaaaaaaaaaaaaaaaaaaa...
注意:即使在这里,您也可以看到regex101具有步骤optimis
Pattern 1: (?:c)at
Pattern 2: cat