为什么s/^\s + |\s + $ // g; 比两个单独的替换慢得多?

Eug*_*ash 13 regex perl trim

Perl FAQ条目如何从字符串的开头/结尾删除空格?声明使用

s/^\s+|\s+$//g;
Run Code Online (Sandbox Code Playgroud)

比分两步做得慢:

s/^\s+//;
s/\s+$//;
Run Code Online (Sandbox Code Playgroud)

为什么这个组合语句明显慢于单独的语句(对于任何输入字符串)?

sid*_*eal 12

使用"固定"或"锚定"子字符串而不是"浮动"子字符串时,Perl正则表达式运行时运行得更快.当您可以将其锁定到源字符串中的某个位置时,会修复子字符串.'^'和'$'都提供锚定.但是,当您使用交替"|"时,编译器不会将选项识别为已修复,因此它使用优化程度较低的代码来扫描整个字符串.并且在该过程结束时,寻找两次固定字符串要比查找一次浮动字符串快得多.在相关的说明中,阅读perl的regcomp.c会让你失明.

更新:这里有一些额外的细节.如果您使用调试支持编译它,则可以使用'-Dr'标志运行perl,并且它将转储正则表达式编译数据.这是你得到的:

~# debugperl -Dr -e 's/^\s+//g'
Compiling REx `^\s+'
size 4 Got 36 bytes for offset annotations.
first at 2
synthetic stclass "ANYOF[\11\12\14\15 {unicode_all}]".
   1: BOL(2)
   2: PLUS(4)
   3:   SPACE(0)
   4: END(0)
stclass "ANYOF[\11\12\14\15 {unicode_all}]" anchored(BOL) minlen 1
Run Code Online (Sandbox Code Playgroud)
# debugperl -Dr -e 's/^\s+|\s+$//g'
Compiling REx `^\s+|\s+$'
size 9 Got 76 bytes for offset annotations.

   1: BRANCH(5)
   2:   BOL(3)
   3:   PLUS(9)
   4:     SPACE(0)
   5: BRANCH(9)
   6:   PLUS(8)
   7:     SPACE(0)
   8:   EOL(9)
   9: END(0)
minlen 1 
Run Code Online (Sandbox Code Playgroud)

请注意第一个转储中的"锚定"一词.

  • 您实际上并不需要perl的调试版本.你需要它来让`-Dr`工作,但没有它你就可以`使用re'debug'`,无论如何都更漂亮. (3认同)

FMc*_*FMc 9

其他答案表明,完全锚定的正则表达式允许引擎优化搜索过程,只关注开头或结尾或字符串.通过使用不同长度的字符串比较两种方法的速度差异,您似乎可以看到此优化的效果.随着字符串变长,"浮动"正则表达式(使用交替)受到越来越多的影响.

use strict;
use warnings;
use Benchmark qw(cmpthese);

my $ws = "   \t\t\n";

for my $sz (1, 10, 100, 1000){
    my $str = $ws . ('Z' x $sz) . $ws;
    cmpthese(-2, {
        "alt_$sz" => sub { $_ = $str; s/^\s+|\s+$//g },
        "sep_$sz" => sub { $_ = $str; s/^\s+//; s/\s+$// },
    });
}

           Rate alt_1 sep_1
alt_1  870578/s    --  -16%
sep_1 1032017/s   19%    --

            Rate alt_10 sep_10
alt_10  384391/s     --   -62%
sep_10 1010017/s   163%     --

            Rate alt_100 sep_100
alt_100  61179/s      --    -92%
sep_100 806840/s   1219%      --

             Rate alt_1000 sep_1000
alt_1000   6612/s       --     -97%
sep_1000 261102/s    3849%       --
Run Code Online (Sandbox Code Playgroud)