Я задавался вопросом, существует ли более хороший, но краткий путь к разделению строки в ее символы
@characters = split //, $string
это не трудно считать, но так или иначе использование регулярного выражения похоже на излишество мне.
Я придумал это:
@characters = map { substr $string, $_, 1 } 0 .. length($string) - 1
но я нахожу это более ужасным и менее читаемым. Каков Ваш предпочтительный способ разделить ту строку на ее символы?
Почему использование регулярного выражения будет "излишним"? Многие беспокоятся, что регулярных выражений в Perl слишком много, потому что они думают, что их запуск требует очень сложного и медленного алгоритма регулярных выражений. Это не всегда верно: реализация сильно оптимизирована, и многие простые случаи рассматриваются специально: то, что выглядит как регулярное выражение, на самом деле может работать так же, как простой поиск подстроки. Я не удивлюсь, если этот тип разделения
также будет оптимизирован. split
на быстрее, чем ваша карта
в некоторых тестах, которые я проводил. unpack
выглядит немного быстрее, чем split
.
Я рекомендую split
, потому что это «идиоматический» способ. Вы найдете его в perldoc, во многих книгах, и любой хороший программист на Perl должен это знать (если вы не уверены, что ваша аудитория поймет это, вы всегда можете добавить комментарий к коду, как кто-то предложил).
OTOH , если регулярные выражения "избыточны" только потому, что синтаксис уродлив, то для меня это слишком субъективно, чтобы что-то говорить. ; -)
Используйте split
с шаблоном NULL, чтобы разбить строку на отдельные символы:
@characters = split //, $string;
Если вам просто нужны коды символов, используйте unpack:
@values = unpack("C*", $string);
Вам может потребоваться включить , используйте utf8
для правильной работы распаковки. И вы также можете использовать unpack
+ chr
, чтобы разделить строку на отдельные символы, просто TMTOWTDI:
@characters = map chr, unpack("C*", $string);
Это не намного яснее, чем использование функции split
для split ] строка. Я полагаю, вы могли бы возразить, что шаблон null не интуитивно понятен; хотя я нахожу это достаточно ясным. Если вам нужна «чистая» альтернатива, заключите ее в подпрограмму:
my @characters = chars($string);
sub chars { split //, $_[0] }
Я подумал, что было бы неплохо посмотреть, насколько быстро некоторые способы разбить строку на каждый символ.
Я провел тест на нескольких версиях 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 », ...
.
Вы правы. Стандартный способ сделать это - split //, $ string
. Чтобы сделать код более читабельным, вы можете создать простую функцию:
sub get_characters {
my ($string) = @_;
return ( split //, $string );
}
@characters = get_characters($string);
Я предпочитаю использовать технику split . Это хорошо известно и задокументировано.
Еще один способ ...
@characters = $string =~ /./gs;
Для менее читабельного и более краткого (и все еще с перебором regex):
@characters = $string =~ /./g;
(Я научился этой идиоме, играя в код-гольф)
.