开发者

Map with Split & Trim in Perl

How do I use map with the split function to trim the constituents: $a, $b, $c and $d; of $line?

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

# Perl trim function to remove whitespace from the start a开发者_如何学编程nd end of the string
sub trim($)
{
    my $string = shift;
    $string =~ s/^\s+//;
    $string =~ s/\s+$//;
    return $string;
}


Don't use prototypes the ($) on your function unless you need them.

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

Don't forget in the above s/// returns the replacement count -- not $_. So, we do that explicitly.

or more simply:

my @values = map {s/^\s+|\s+$//g; $_}, split(/\t/, $line, 5), $line


map takes two inputs:

  • an expression or block: this would be the trim expression (you don't have to write your own -- it's on CPAN)
  • and a list to operate on: this should be split's output:
use String::Util 'trim';
my @values = map { trim($_) } split /\t/, $line;


This should work:

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

By the way, it's a minor point, but you should not use $a and $b as variable names.


You can also use "foreach" here.

foreach my $i ($a, $b, $c, $d, $e) {
  $i=trim($i);
}


Just for variety:

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

grep acts as a filter on lists. This is why the \s+s need to be changed to \s*s inside the regex. Forcing matches on 0 or more spaces prevents grep from filtering out items in the list that have no leading or trailing spaces.


When I trim a string, I don't often want to keep the original. It would be nice to have the abstraction of a sub but also not have to fuss with temporary values.

It turns out that we can do just this, as perlsub explains:

Any arguments passed in show up in the array @_. Therefore, if you called a function with two arguments, those would be stored in $_[0] and $_[1]. The array @_ is a local array, but its elements are aliases for the actual scalar parameters. In particular, if an element $_[0] is updated, the corresponding argument is updated (or an error occurs if it is not updatable).

In your case, trim becomes

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

Remember that map and for are cousins, so with the loop in trim, you no longer need map. For example

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";

Output:

BEFORE: [1] [ 2] [3 ] [ 4 ]
AFTER:  [1] [2] [3] [4]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜