Карта с Split & Trim в Perl - PullRequest
       43

Карта с Split & Trim в Perl

4 голосов
/ 02 июля 2010

Как использовать map с функцией split для обрезки составляющих: $ a, $ b, $ c и $ d; $ line?

my ($a, $b, $c, $d, $e) = split(/\t/, $line);

# Perl trim function to remove whitespace from the start and end of the string
sub trim($)
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}

Ответы [ 6 ]

4 голосов
/ 02 июля 2010

Не используйте прототипы ($) в своей функции, если вам не нужно их.

my ( $a, $b, $c, $d, $e ) =
  map {s/^\s+|\s+$//g; $_}    ## Notice the `, $_` this is common
  , split(/\t/, $line, 5)
;

Не забудьте в приведенном выше s/// возвращает счетчик замены -- не $_.Итак, мы делаем это явно.

или проще:

my @values = map {s/^\s+|\s+$//g; $_}, split(/\t/, $line, 5), $line
3 голосов
/ 02 июля 2010

map принимает два входа:

  • выражение или блок: это будет выражение trim (вам не нужно писать свое собственное - оно на CPAN)
  • и список для работы: это должен быть вывод split:
use String::Util 'trim';
my @values = map { trim($_) } split /\t/, $line;
2 голосов
/ 02 июля 2010

Это должно работать:

my ($a, $b, $c, $d, $e) = map {trim ($_)} (split(/\t/, $line));

Кстати, это второстепенная точка, но вы не должны использовать $ a и $ b в качестве имен переменных.

1 голос
/ 02 июля 2010

Вы также можете использовать здесь «foreach».

foreach my $i ($a, $b, $c, $d, $e) {
  $i=trim($i);
}
0 голосов
/ 02 июля 2010

Когда я обрезаю строку, я не часто хочу сохранить оригинал.Было бы неплохо иметь абстракцию подпрограммы, но также не нужно суетиться с временными значениями.

Оказывается, что мы можем сделать это, как объясняет perlsub :

Все переданные аргументы отображаются в массиве @_.Следовательно, если вы вызываете функцию с двумя аргументами, они будут храниться в $_[0] и $_[1].Массив @_ является локальным массивом, но его элементы являются псевдонимами для фактических скалярных параметров.В частности, если элемент $_[0] обновляется, соответствующий аргумент обновляется (или возникает ошибка, если он не обновляется).

В вашем случае trim становится

sub trim {
  for (@_) {
    s/^ \s+  //x;
    s/  \s+ $//x;
  }
  wantarray ? @_ : $_[0];
}

Помните, что map и for являются двоюродными братьями, поэтому с циклом в trim вам больше не нужно map.Например,

my $line = "1\t 2\t3 \t 4 \t  5  \n";    
my ($a, $b, $c, $d, $e) = split(/\t/, $line);    

print "BEFORE: [", join("] [" => $a, $b, $c, $d), "]\n";
trim $a, $b, $c, $d;
print "AFTER:  [", join("] [" => $a, $b, $c, $d), "]\n";

Вывод:

BEFORE: [1] [ 2] [3 ] [ 4 ]
AFTER:  [1] [2] [3] [4]
0 голосов
/ 02 июля 2010

Только для разнообразия:

my @trimmed = grep { s/^\s*|\s*$//g } split /\t/, $line;

grep действует как фильтр в списках. Вот почему \s+ s нужно изменить на \s* s внутри регулярного выражения. Формирование совпадений на 0 или более пробелах не позволяет grep отфильтровывать элементы в списке, у которых нет начальных или конечных пробелов.

...