在Perl中,将字符串转换为字符列表的理智方法是什么?

时间:2010-03-01 14:23:29

标签: perl string split

我一直在想是否有一种更好,更简洁的方法将字符串拆分为字符

@characters = split //, $string

并不难读,但不知怎的,使用正则表达式对我来说太过分了。

我想出了这个:

@characters = map { substr $string, $_, 1 } 0 .. length($string) - 1

但我发现它更丑陋且不太可读。将字符串拆分为字符的首选方法是什么?

7 个答案:

答案 0 :(得分:9)

各种示例和速度比较。

我认为看一下在每个角色上分割字符串的方法有多快是个好主意。

我对我碰巧在计算机上安装的几个Perl版本进行了测试。

test.pl

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

Perl v5.10.0

               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%           --

Perl v5.10.1

               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%           --

Perl v5.11.2

               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)

我更喜欢使用split技术。它是众所周知的,并且有记录。

又一种方式......

@characters = $string =~ /./gs;

答案 6 :(得分:2)

使用带有空模式的split将字符串分解为单个字符:

@characters = split //, $string;

如果您只想要char代码,请使用unpack:

@values = unpack("C*", $string);

您可能需要包含use utf8才能解压缩才能正常使用。您还可以使用unpack + chr将字符串拆分为单个字符,只需TMTOWTDI:

@characters = map chr, unpack("C*", $string);