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]
精彩评论