2015-10-02 2 views
2

Я пытаюсь разбить строку и вывести значение из возвращаемого массива. Как я могу сделать это в одной строке?Perl split и pop в одной строке

my $string = 'test,string'; 

# Split and pop in one line 
my $val = pop [split ',', $string]; 

print $val; 

Результат должен быть 'string', но вместо этого я получаю это:

Тип арг 1 поп должен быть массив (не анонимный список ([]))


Вот моя информация о версии на Perl, если это помогает:

Это Perl, v5.8.8 построен для x86_64-Linux-нить-мульти

+1

Почему вы хотите сделать это в одной строке? – Borodin

ответ

2

Если ваша цель, чтобы получить последнее поле после некоторого числа запятых, Есть несколько способов - некоторый путь быстрее, чем другие.

Жадный регулярное выражение с шаблоном разделителем + шаблон поля будет общим, легко читать, и быстро:

/.*(delimiter pattern)(field_pattern)/ 

.* отстой ИБП все символы, за исключением последней инстанции разделителем. Затем шаблон поля возвращает последнее поле.

Используя привязанный раскол (так, что только две части будут возвращены) также идиоматичен:

my ($lh, $rh)=split(/([^,]+)$/, $string); 

Теперь $rh имеет последний элемент раскола (и $lh имеет часть слева от последнего поля).

быстрый (если $string является длинноватым и ваш разделителем инвариантна) будет что-то вроде:

substr $string, rindex($string, ',') + length ','; 

Benchmark этих и некоторых других методов любопытства:

use strict; 
use warnings; 
use Benchmark; 

my $str; 

my %subs = (
    regex => sub { 
     my ($rh) = $str =~ /,([^,]+)$/; 
     return $rh; 
    }, 
    greedy_regex => sub { 
     my ($rh) = $str =~ /.*,([^,]+)$/; 
     return $rh; 
    }, 
    split_once => sub { 
     my ($lh, $rh)=split(/([^,]+)$/, $str, 2); 
     return $rh; 
    }, 
    split_slice => sub { 
     my ($rh) = (split /,/, $str)[-1]; 
     return $rh; 
    }, 
    pop => sub { 
     my ($rh) = pop @{[split ',', $str]}; 
     return $rh; 
    }, 
    rindex => sub { 
     my ($rh) = substr $str, rindex($str, ',') + length ','; 
     return $rh; 
    } 
); 

for my $n (10, 100, 1000, 10000) { 
    $str=join(',', (1..$n)); 
    my @results=(); 
    for my $sub (keys %subs) { 
     my [email protected]{[$subs{$sub}()]}[0]; 
     if ($ret ne $n){ 
      print "$sub: $ret != $n\n"; 
     } 
     else { 
      push @results, $sub; 
     } 
    } 
    my $l=length($str); 
    print join(', ', @results)," all returned \"$n\" from a string $l characters long\n"; 
    Benchmark::cmpthese -1, \%subs; 
    print "\n"; 
} 

распечаток:

split_once, pop, split_slice, regex, rindex, greedy_regex all returned "10" from a string 20 characters long 
        Rate  pop split_once split_slice regex greedy_regex rindex 
pop   295080/s  --  -46%  -49% -57%   -86% -95% 
split_once 546132/s  85%   --   -5% -21%   -75% -91% 
split_slice 573439/s  94%   5%   -- -17%   -74% -91% 
regex   689852/s 134%  26%   20%  --   -68% -89% 
greedy_regex 2182991/s 640%  300%  281% 216%   -- -65% 
rindex  6230669/s 2012%  1041%  987% 803%   185%  -- 

split_once, pop, split_slice, regex, rindex, greedy_regex all returned "100" from a string 291 characters long 
        Rate pop split_slice regex split_once greedy_regex rindex 
pop   29020/s  --  -50% -54%  -54%   -98% -100% 
split_slice 57961/s 100%   --  -8%  -9%   -96% -99% 
regex   63015/s 117%   9%  --  -1%   -96% -99% 
split_once  63433/s 119%   9%  1%   --   -96% -99% 
greedy_regex 1536000/s 5193%  2550% 2338%  2321%   -- -75% 
rindex  6068148/s 20810%  10369% 9530%  9466%   295%  -- 

split_once, pop, split_slice, regex, rindex, greedy_regex all returned "1000" from a string 3892 characters long 
        Rate  pop regex split_once split_slice greedy_regex rindex 
pop    3428/s  -- -36%  -40%  -50%   -99% -100% 
regex   5333/s  56%  --  -7%  -23%   -99% -100% 
split_once  5749/s  68%  8%   --  -17%   -99% -100% 
split_slice  6892/s 101%  29%  20%   --   -98% -100% 
greedy_regex 417552/s 12082% 7730%  7163%  5958%   -- -93% 
rindex  6036210/s 176002% 113085% 104894%  87479%  1346%  -- 

split_once, pop, split_slice, regex, rindex, greedy_regex all returned "10000" from a string 48893 characters long 
        Rate  pop regex split_once split_slice greedy_regex rindex 
pop    355/s  --  -24%  -29%  -51%   -99% -100% 
regex   465/s  31%  --  -7%  -35%   -99% -100% 
split_once  501/s  41%  8%   --  -30%   -99% -100% 
split_slice  718/s  102%  54%  43%   --   -99% -100% 
greedy_regex 59076/s 16530% 12603%  11692%  8126%   -- -99% 
rindex  5770465/s 1624294% 1240731% 1151756%  803382%  9668%  -- 

greedy_regex, split_slice, split_once, regex, pop, rindex all returned correctly with "10000" from a string 48893 characters long 
        Rate  pop split_once regex split_slice greedy_regex rindex 
pop    383/s  --  -26%  -26%  -45%   -99% -100% 
split_once  516/s  35%   --  -0%  -26%   -99% -100% 
regex   519/s  35%   0%  --  -25%   -99% -100% 
split_slice  693/s  81%  34%  34%   --   -99% -100% 
greedy_regex 59076/s 15311%  11349% 11293%  8425%   -- -99% 
rindex  6109904/s 1593788% 1183990% 1178239%  881582%  10242%  -- 

Вы можете видеть, что rindex на сегодняшний день является самым быстрым с жадным регулярным выражением, очень полезным. Если строка немногочисленна и коротка, я полагаю, вы можете использовать любой, который уравновешивает идиому и читаемость, и это ваше решение.

+0

Работает ли ваш «самый быстрый» метод, если строка содержит несколько «,»? – tjwrona1992

+0

Да. 'rindex' находит последний символ (самый правый) в строке. Посмотрите на [этот тест] (http://www.perlmonks.org/?node_id=985564) в середине страницы. – dawg

+0

Вау, я даже не слышал о «rindex». Потрясающие! – tjwrona1992

7

[] возвращает ссылку на массив, но pop ожидает фактический массив, поэтому решение разыменовать массива следующим образом:

my $val = pop @{[split ',', $string]}; 
+0

Спасибо за разъяснение @ikegami. Я бы поднял его, но я не могу голосовать за свой пост :( – tjwrona1992

+1

Начиная с Perl 5.14 вы можете поместить ссылку на массив, так что 'my $ val = pop [split ',', $ string];' будет работать. думаю, что это зло, хотя! – mwp

+0

Его также экспериментальный. Он работает на моем ПК с ОС Windows (Perl v 5.20), но он дает предупреждение «Поп-ссылка является экспериментальной». – tjwrona1992

8

push, pop, shift и unshift предназначены для манипулирования массивами. Похоже, вы просто хотите получить последнее значение из списка, возвращаемого split, который вы можете получить с ломтиком списка:

my $val = (split /,/, $foo)[-1]; 
+0

Это тоже работает! :) – tjwrona1992

+1

Его смешно, я не понимал, что существует разница между «списком» и «массивом» в Perl .. . Ты узнаешь что-то новое каждый день! – tjwrona1992

+1

@ tjwrona1992 Это очень важное различие, с которым сталкиваются многие программисты на Perl. Я бы рекомендовал прочитать [Массивы против списков в Perl: в чем разница?] (Http://friedo.com/blog/2013/07/arrays-vs-lists-in-perl) – ThisSuitIsBlackNot

1

Если эффективность является проблемой, просто использовать регулярные выражения. Разделение строк и всплывающих массивов (потенциально) дорого.

my ($val) = $string =~ /,(\w+)$/ 
+1

Разделение в общем случае происходит быстрее, чем совпадение. Несмотря на прохождение шаблона регулярного выражения, используется гораздо более легкий двигатель. – ikegami

+0

@ikegami, это правда даже для предварительно скомпилированных регулярных выражений с использованием 'qr {}'? – tjwrona1992

+0

Да, я так думаю. Не уверен, что конкретно отличается, но тесты говорят сами за себя. – ikegami