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

在Perl中,将字符串转换为字符列表的明智方法是什么?,perl,string,split,Perl,String,Split,我一直在想,是否有一种更好、更简洁的方法可以将字符串拆分为字符 @characters = split //, $string 这并不难理解,但不知何故,正则表达式的使用在我看来似乎有些过分了 我想到了这个: @characters = map { substr $string, $_, 1 } 0 .. length($string) - 1 但我觉得它更难看,可读性也更低。您喜欢用什么方式将该字符串拆分为字符?您说得对。执行此操作的标准方法是split/,$string。为了使代码更具可

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

@characters = split //, $string
这并不难理解,但不知何故,正则表达式的使用在我看来似乎有些过分了

我想到了这个:

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

但我觉得它更难看,可读性也更低。您喜欢用什么方式将该字符串拆分为字符?

您说得对。执行此操作的标准方法是
split/,$string
。为了使代码更具可读性,您可以创建一个简单的函数:

sub get_characters {
    my ($string) = @_;
    return ( split //, $string );
}

@characters = get_characters($string);

没有比使用
split
函数拆分字符串更清楚的了。我想你可以说空模式是不直观的;虽然我觉得很清楚。如果您想要一个“干净”的备选方案,请将其包装在子组件中:

my @characters = chars($string);
sub chars { split //, $_[0] }

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

@characters = split //, $string;
如果您只需要字符代码,请使用解包:

@values = unpack("C*", $string);
您可能需要包括
使用utf8
,才能使解包正常工作。您还可以使用
unpack
+
chr
将字符串拆分为单个字符,只需TMTOWTDI:

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

对于可读性较差且更简洁的(仍然使用regex overkill):

(我从打代码高尔夫中学到这个成语。)

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

还有另一种方式

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

为什么使用正则表达式会“过分”呢?许多人担心Perl中的正则表达式过于死板,因为他们认为运行它们需要一个高度复杂且缓慢的正则表达式算法。这并不总是正确的:实现是高度优化的,并且许多简单的情况都经过了特殊处理:看起来像正则表达式的东西实际上可以执行简单的子字符串搜索。如果这种类型的
split
也得到了优化,我一点也不会感到惊讶<代码>拆分比我运行的一些测试中的
映射
更快<代码>解包似乎略快于
拆分

我建议使用
split
,因为这是一种“惯用”方式。您可以在perldoc和许多书籍中找到它,任何优秀的Perl程序员都应该知道它(如果您不确定您的读者是否理解它,您可以像某人建议的那样向代码中添加注释)

OTOH,如果正则表达式只是因为语法难看而被“过度使用”,那么我就太主观了,不能说任何话

各种示例和速度比较。 我想看看有些方法在每个字符上拆分字符串的速度有多快可能是个好主意

我在计算机上运行了几个Perl版本的测试

test.pl
用于perl-in/usr/bin/perl/opt/perl-5.10.1/bin/perl/opt/perl-5.11.2/bin/perl;
做
$perl-v | perl-nlE'if(/(v5\.\d+\.\d+/){
说“##Perl$1”;
说“”;
最后;
}';
$perl test.pl;
echo-e'\n';
完成
Perl v5.10.0 速率拆分捕获匹配捕获映射子字符串匹配解包拆分字符串 拆分捕获296/s--20%-20%-23%-58%-63%-63% 匹配捕获368/s 24%--0%-4%-48%-54%-54% 地图substr 370/s 25%0%--3%-48%-53%-54% 匹配382/s 29%4%3%--46%-52%-52% 打开709/s 140%93%92%86%--11%-11% 拆分793/s 168%115%114%107%12%--0% 拆分字符串795/s 169%116%115%108%12%0%-- PerlV5.10.1 速率拆分捕获映射子字符串匹配捕获匹配解包拆分字符串 拆分捕获301/s--31%-41%-47%-60%-65%-66% 地图substr 435/s 45%--14%-23%-42%-50%-50% 匹配捕获506/s 68%16%--10%32%42%42% 匹配565/s 88%30%12%--24%-35%-35% 开箱743/s 147%71%47%32%--15%-15% 分割869/s 189%100%72%54%17%--1% 拆分字符串875/s 191%101%73%55%18%1%-- PerlV5.11.2 速率拆分捕获匹配捕获匹配映射substr解包拆分字符串拆分 拆分捕获速度为300/s--28%-32%-38%-59%-63%-63% 匹配捕获420/s 40%--5%-13%-42%-48%-49% 匹配441/s 47%5%--9%-39%-46%-46% 地图substr 482/s 60%15%9%--34%41%41% 拆包727/s 142%73%65%51%--10%-11% 拆分字符串811/s 170%93%84%68%12%--1% 分割816/s 171%94%85%69%12%1%-- 正如您所看到的,split是最快的,因为这是
split
代码中的一个特例

拆分捕获速度最慢,可能是因为它必须设置
$1
,以及其他几个匹配变量


因此,我建议使用普通的
split//,…
,或大致相当的
split',…

。。。并在sub中添加注释来描述实现。这是令人厌恶的令人兴奋的方式+1:-)如果你的座右铭是“千方百计,选择最难读懂的方法”,那么这是一个不错的候选人。我不太擅长学习新的习惯用法,但打包/解包不知何故逃脱了我的控制。问题是,这比拆分快吗?
@characters=unpack'(a)*',$string似乎也起作用。让我们看看还能挖到什么。
@characters = $string =~ /./gs;
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% --