Perl:最快的匹配任何字符?

3

我想在不使用 /s 的情况下完成这个操作:

(?:.|\n)+

我希望它快速。

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

perl -pe 's/(?:.|\n)+//'  #  30 MBytes/s
perl -pe 's/[^\777]+//'   # 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

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


1
[\d\D][\s\S] 等呢? - choroba
1
关于(?s:.)的修改以及您列出的其他选项,它们都将产生完全相同的正则表达式程序,因此它们的性能是相同的。[\d\D][\s\S]是解决方法,只在5.24之后才起作用,因此这些选项更差。而(?s:.)(?s).+(?-s)更好,因为它恢复了s标志而不是关闭它。(它也更短。) - ikegami
3个回答

2
如果我创建一个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/[^\777]+//' 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
    

正如您所看到的,自5.24版本以来,[\s\S]字符类已被优化为/./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]"

2

您不需要使用任何变通方法。

您可以使用行内修改标记,(?s) 以启用点跨越多行匹配效果,并使用 (?-s) 以禁用此效果。

例如:

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

第一个 .* 匹配任何文本,而最后一个 .* 只匹配到行末。

你还可以使用修饰符组:

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

更多内容请参见扩展模式


2
您可以使用(?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] 一样是一种变通方法。

尽管如此,自从 5.24 版本以来,(?s:.)(?s).(?-s)[\s\S][\d\D] 都会产生完全相同的正则表达式程序,因此它们的性能都相同。


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