我一直在想是否有一种更好,更简洁的方法将字符串拆分为字符
@characters = split //, $string
并不难读,但不知怎的,使用正则表达式对我来说太过分了。
我想出了这个:
@characters = map { substr $string, $_, 1 } 0 .. length($string) - 1
但我发现它更丑陋且不太可读。将字符串拆分为字符的首选方法是什么?
答案 0 :(得分:9)
我认为看一下在每个角色上分割字符串的方法有多快是个好主意。
我对我碰巧在计算机上安装的几个Perl版本进行了测试。
use 5.010;
use Benchmark qw(:all) ;
my %bench = (
'split' => sub{
state $string = 'x' x 1000;
my @chars = split //, $string;
\@chars;
},
'split-string' => sub{
state $string = 'x' x 1000;
my @chars = split '', $string;
\@chars;
},
'split-capture' => sub{
state $string = 'x' x 1000;
my @chars = split /(.)/, $string;
\@chars;
},
'unpack' => sub{
state $string = 'x' x 1000;
my @chars = unpack( '(a)*', $string );
\@chars;
},
'match' => sub{
state $string = 'x' x 1000;
my @chars = $string =~ /./gs;
\@chars;
},
'match-capture' => sub{
state $string = 'x' x 1000;
my @chars = $string =~ /(.)/gs;
\@chars;
},
'map-substr' => sub{
state $string = 'x' x 1000;
my @chars = map { substr $string, $_, 1 } 0 .. length($string) - 1;
\@chars;
},
);
# set the initial state of $string
$_->() for values %bench;
cmpthese( -10, \%bench );
for perl in /usr/bin/perl /opt/perl-5.10.1/bin/perl /opt/perl-5.11.2/bin/perl;
do
$perl -v | perl -nlE'if( /(v5\.\d+\.\d+)/ ){
say "## Perl $1";
say "<pre>";
last;
}';
$perl test.pl;
echo -e '</pre>\n';
done
Rate split-capture match-capture map-substr match unpack split split-string split-capture 296/s -- -20% -20% -23% -58% -63% -63% match-capture 368/s 24% -- -0% -4% -48% -54% -54% map-substr 370/s 25% 0% -- -3% -48% -53% -54% match 382/s 29% 4% 3% -- -46% -52% -52% unpack 709/s 140% 93% 92% 86% -- -11% -11% split 793/s 168% 115% 114% 107% 12% -- -0% split-string 795/s 169% 116% 115% 108% 12% 0% --
Rate split-capture map-substr match-capture match unpack split split-string split-capture 301/s -- -31% -41% -47% -60% -65% -66% map-substr 435/s 45% -- -14% -23% -42% -50% -50% match-capture 506/s 68% 16% -- -10% -32% -42% -42% match 565/s 88% 30% 12% -- -24% -35% -35% unpack 743/s 147% 71% 47% 32% -- -15% -15% split 869/s 189% 100% 72% 54% 17% -- -1% split-string 875/s 191% 101% 73% 55% 18% 1% --
Rate split-capture match-capture match map-substr unpack split-string split split-capture 300/s -- -28% -32% -38% -59% -63% -63% match-capture 420/s 40% -- -5% -13% -42% -48% -49% match 441/s 47% 5% -- -9% -39% -46% -46% map-substr 482/s 60% 15% 9% -- -34% -41% -41% unpack 727/s 142% 73% 65% 51% -- -10% -11% split-string 811/s 170% 93% 84% 68% 12% -- -1% split 816/s 171% 94% 85% 69% 12% 1% --
正如您所见, split 是最快的,因为这是split
代码中的特殊情况。
split-capture 是最慢的,可能是因为它必须设置$1
以及其他几个匹配变量。
所以我建议使用普通的split //, ...
或大致相当的split '', ...
。
答案 1 :(得分:6)
为什么使用正则表达式会“过度杀伤”?许多人担心Perl中的正则表达式过度,因为他们认为运行它们涉及高度复杂和缓慢的正则表达式算法。这并非总是如此:实现是高度优化的,并且特别处理了许多简单的情况:看起来像正则表达式实际上可以执行的操作和简单的子字符串搜索一样。如果这种类型的split
也得到优化,我也不会感到惊讶。在我运行的某些测试中,split
比map
更快。 unpack
似乎比split
略快。
我推荐split
,因为它是“惯用”方式。您可以在perldoc,许多书籍中找到它,并且任何优秀的Perl程序员都应该知道它(如果您不确定您的受众是否会理解它,您可以随时向代码添加注释,就像有人建议的那样。)
OTOH,如果正则表达式“过度杀戮”只是因为语法很难看,那么对我来说说话太客观了。 ; - )
答案 2 :(得分:5)
使用split
函数拆分字符串并没有更清楚。我想你可以说零点模式是不直观的;虽然我觉得很清楚。如果你想要一个“干净”的替代品将它包装在一个子:
my @characters = chars($string);
sub chars { split //, $_[0] }
答案 3 :(得分:5)
对于不太可读和更简洁(并且仍然使用正则表达式矫枉过正):
@characters = $string =~ /./g;
(我从打代码高尔夫中学到了这个成语。)
答案 4 :(得分:4)
split //, $string
。为了使代码更具可读性,您可以创建一个简单的函数:
sub get_characters {
my ($string) = @_;
return ( split //, $string );
}
@characters = get_characters($string);
答案 5 :(得分:4)
答案 6 :(得分:2)
使用带有空模式的split
将字符串分解为单个字符:
@characters = split //, $string;
如果您只想要char代码,请使用unpack:
@values = unpack("C*", $string);
您可能需要包含use utf8
才能解压缩才能正常使用。您还可以使用unpack
+ chr
将字符串拆分为单个字符,只需TMTOWTDI:
@characters = map chr, unpack("C*", $string);