Perl 常见问题解答条目如何从字符串的开头/结尾去除空格?指出使用
s/^\s+|\s+$//g;
比分两步做要慢:
s/^\s+//;
s/\s+$//;
为什么这个组合语句明显比单独的语句慢(对于任何输入字符串)?
Perl 常见问题解答条目如何从字符串的开头/结尾去除空格?指出使用
s/^\s+|\s+$//g;
比分两步做要慢:
s/^\s+//;
s/\s+$//;
为什么这个组合语句明显比单独的语句慢(对于任何输入字符串)?
当使用“固定”或“锚定”子字符串而不是“浮动”子字符串时,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
# 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
请注意第一个转储中的“锚定”一词。
其他答案表明,完全锚定的正则表达式允许引擎优化搜索过程,只关注开头或结尾或字符串。通过使用不同长度的字符串比较两种方法的速度差异,您似乎可以看到这种优化的效果。随着字符串变长,“浮动”正则表达式(使用交替)受到越来越多的影响。
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% --
由于这两种方法在逻辑上是等价的,因此它们没有内在的理由在评估性能上存在差异。然而,在实践中,一些引擎将无法在更复杂的正则表达式中发现优化。
^\s+
在这种情况下,组合的正则表达式作为一个整体是未锚定的,因此它可能会匹配字符串中的任何点,\s+$
而从末尾向后的每个字符的单个字符类 - 一个经过良好优化的引擎将识别该事实并将反向匹配,这使得它^\s+
与输入反向的匹配一样微不足道。
如果确实如此,那将是因为正则表达式引擎能够比组合正则表达式更好地优化单个正则表达式。
“明显变慢”是什么意思?