Perl:最快的比赛?

Perl: Fastest match of anything?

我想在不使用 /s 的情况下执行此操作:

(?:.|\n)+

我希望它快点。

它是一个更大的正则表达式的一部分,这就是我不能使用 /s 的原因。我测试过:

perl -pe 's/(?:.|\n)+//'  #  30 MBytes/s
perl -pe 's/[^7]+//'   # 124 MBytes/s

它们没有 /s 快:

perl -pe 's/.+//s'        # 164 MBytes/s

我能以某种方式获得与 /s 相同的速度吗?

编辑:

perl -pe 's/(?s).+(?-s)//' # 162 MBytes/s
perl -pe 's/[\d\D]+//'    # 162 MBytes/s
perl -pe 's/[\s\S]+//'    # 161 MBytes/s

这些都是不错的选择。谢谢

您不需要使用任何解决方法。

您可以使用内联修饰符标志,(?s) 启用点以跨行匹配,(?-s) 禁用此效果。

例如:

(?s).*PATTERN(?-s).*

第一个 .* 匹配任何文本,最后一个 .* 只匹配到一行的结尾。

您还可以使用修饰符组:

(?s:.*)PATTERN(?-s:.*)

更多内容见Extended Patterns

您可以使用 (?s:PATTERN) 为括号中的子模式启用 /s

(?s:.)+

(?s:.+)

例如,

$ perl -M5.010 -e'
   say /^.(?s:.).\z/ ? "match" : "no match"
      for "\n\n\n", "A\n\n", "\n\nA", "A\nA";
'
no match
no match
no match
match

./s(?s:.) 之间没有区别,因此您将获得完全相同的性能。

$ perl -Mre=debug -e'qr/(?s:.)/'
Compiling REx "(?s:.)"
Final program:
   1: SANY (2)
   2: END (0)
minlen 1
Freeing REx: "(?s:.)"

$ perl -Mre=debug -e'qr/./s'
Compiling REx "."
Final program:
   1: SANY (2)
   2: END (0)
minlen 1
Freeing REx: "."

相对于其他解决方案的优势:

  • (?s:.) 恢复 s 标志状态,而 (?s).(?-s) 将其关闭。
  • (?s:.)(?s).(?-s).
  • 短一点
  • (?s:.) 不长于 [\s\S][\d\D].
  • (?s:.) 不是像 [\s\S][\d\D] 那样的解决方法。

也就是说,(?s:.)(?s).(?-s)[\s\S][\d\D] 都会生成完全相同的正则表达式程序(自 5.24 起),因此它们都会执行一模一样。

如果我创建一个 98MB 的文件:

$ dd bs=1024 count=100000 </dev/urandom >file
100000+0 records in
100000+0 records out
102400000 bytes transferred in 0.558640 secs (183302305 bytes/sec)

现在比较一些方法:

time perl -0777 -lne 's/(?:.|\n)+//' file 
real    0m1.957s
user    0m1.902s
sys 0m0.050s

time perl -0777 -lne 's/[^7]+//' file 
real    0m0.130s
user    0m0.082s
sys 0m0.046s

time perl -0777 -lne 's/[\s\S]+//' file 
real    0m0.065s
user    0m0.022s
sys 0m0.041s

time perl -0777 -lne 's/.+//s'  file 
real    0m0.064s
user    0m0.022s
sys 0m0.038s
    

如您所见,[\s\S]的字符class从5.24开始优化为/./s

$ perl -Mre=debug -e'qr/./s'
Compiling REx "."
Final program:
   1: SANY (2)
   2: END (0)
minlen 1
Freeing REx: "."

$ perl -Mre=debug -e'qr/[\s\S]/'
Compiling REx "[\s\S]"
Final program:
   1: SANY (2)
   2: END (0)
minlen 1
Freeing REx: "[\s\S]"