为啥这个正则表达式调用 substcont 次数过多?

Posted

技术标签:

【中文标题】为啥这个正则表达式调用 substcont 次数过多?【英文标题】:Why was this regex calling substcont an excessive number of times?为什么这个正则表达式调用 substcont 次数过多? 【发布时间】:2010-05-24 16:52:24 【问题描述】:

这更多是出于好奇,因为我无法在 Google 上找到有关此功能的任何有用信息 (CORE::substcont)

在分析和优化一些旧的、缓慢的 XML 解析代码时,我发现以下正则表达式在每次执行该行时调用 substcont 31 次,并且花费了大量时间:

调用次数:10000 时间:2.65s 子调用:320000 子调用时间:1.15s`

  $handle =~s/(>)\s*(<)/$1\n$2/g;
  # spent  1.09s making 310000 calls to main::CORE:substcont, avg 4µs/call
  # spent  58.8ms making  10000 calls to main::CORE:subst, avg 6µs/call

与前一行相比:

调用:10000 时间:371ms 子调用:30000 子调用时间:221ms

  $handle =~s/(.*)\s*(<\?)/$1\n$2/g;
    # spent   136ms making 10000 calls to main::CORE:subst, avg 14µs/call
    # spent  84.6ms making 20000 calls to main::CORE:substcont, avg 4µs/call

substcont 调用的数量非常令人惊讶,尤其是看到我认为第二个正则表达式会更昂贵。显然,这就是为什么分析是一件好事;-)

我随后更改了这两行以删除不必要的反向引用,对行为不良的行产生了显着的结果:

通话次数:10000 时间:393 毫秒 子通话次数:10000 次通话时间:341 毫秒

$handle =~s/>\s*</>\n</g;
  # spent   341ms making 10000 calls to main::CORE:subst, avg 34µs/call
所以,我的问题是 - 为什么原始版本要对 substcont 进行如此多的调用,substcont 甚至在需要这么长时间的正则表达式引擎中做了什么?

【问题讨论】:

...我确信我们可以通过更好的方式进行 XML 处理,但现在我一直在努力改进我们所拥有的东西:-/ 介意发布您正在处理的样本吗? 这只是通过 HTTP POST 的 SOAP (XML) 有效负载。但是,它带有有趣的组合:某些行开头的空格、混合行结束样式、同一行上的多个标签、标签之间的多个换行符、某些标签之间的“插页式”文本。所以这只是一个准备步骤,将内容分成模糊合理的行 - 并不是真正应该支配执行时间的东西:) 【参考方案1】:

substcont 是 Perl 的“替换迭代器”的内部名称。与s/// 有关。根据我掌握的少量信息,似乎在进行反向引用时会触发 substcont。也就是说,当$1 存在时。您可以使用 B::Concise 稍微玩一下。

这是一个没有反向引用的简单正则表达式的操作码。

$ perl -MO=Concise,-exec -we'$foo = "foo";  $foo =~ s/(foo)/bar/ig'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:
3  <$> const[PV "foo"] s
4  <#> gvsv[*foo] s
5  <2> sassign vKS/2
6  <;> nextstate(main 1 -e:1) v:
7  <#> gvsv[*foo] s
8  <$> const[PV "bar"] s
9  </> subst(/"(foo)"/) vKS
a  <@> leave[1 ref] vKP/REFC
-e syntax OK

还有一个。

$ perl -MO=Concise,-exec -we'$foo = "foo";  $foo =~ s/(foo)/$1/ig'
1  <0> enter 
2  <;> nextstate(main 1 -e:1) v:
3  <$> const[PV "foo"] s
4  <#> gvsv[*foo] s
5  <2> sassign vKS/2
6  <;> nextstate(main 1 -e:1) v:
7  <#> gvsv[*foo] s
8  </> subst(/"(foo)"/ replstart->9) vKS
9      <#> gvsv[*1] s
a      <|> substcont(other->8) sK/1
b  <@> leave[1 ref] vKP/REFC
-e syntax OK

这就是我所能提供的。您可能想尝试Rx,mjd 的旧正则表达式调试器。

【讨论】:

以上是关于为啥这个正则表达式调用 substcont 次数过多?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个正则表达式不匹配这个文本?

为啥这个正则表达式不生成匹配?

为啥这个正则表达式匹配?

为啥这个正则表达式模式不匹配? [复制]

为啥这个正则表达式模式不能按预期工作?

为啥这个 javascript 正则表达式不起作用?