2010-07-02 6 views
4

Comment utiliser map avec la fonction split pour découper les constituants: $ a, $ b, $ c et $ d; de $ line?Mappage avec Split & Trim en Perl

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

Répondre

2

Cela devrait fonctionner:

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

Par ailleurs, il est un point mineur, mais vous ne devriez pas utiliser un $ et $ b comme noms de variables.

3

map prend deux entrées:

  • une expression ou d'un bloc: ce serait l'expression trim (vous ne devez pas écrire votre propre - il est sur CPAN)
  • et une liste pour fonctionner sur: cela devrait être split la sortie « :
use String::Util 'trim'; 
my @values = map { trim($_) } split /\t/, $line; 
+1

Je suis nerveux à l'idée d'une dépendance à l'introduction d'un module qui dit « Version finale A partir de cette chaîne de version :: Util n'est plus en cours de développement ou d'être pris en charge. " –

+0

Si nous allons installer un module CPAN, nous pourrions aussi bien utiliser celui qui fait le mieux le travail: ['String :: Strip'] (http://p3rl.org/String::Strip). Voir http://www.illusori.co.uk/perl/2010/03/05/advanced_benchmark_analysis_1.html – daxim

+0

Je ne l'ai pas essayé, mais le test d'acidité pour ces types de modules est de savoir s'ils suppriment des choses comme Unicode 0x3000 de la chaîne. Si ce n'est pas le cas, peut-être que ce n'est pas un bon remplacement. Jetant un coup d'œil sur le code source, String :: Strip utilise la fonction C 'isspace' pour enlever les espaces et n'a aucune conscience de l'unicode, donc il se comportera différemment de ce qui précède. –

4

ne pas utiliser des prototypes le ($) sur votre fonction à moins que vous besoin de eux.

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

Ne pas oublier dans ce qui précède s/// renvoie le nombre de remplacement - non $_. Donc, nous le faisons explicitement.

ou plus simplement:

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

pourquoi le vote vers le bas? –

+0

Je ne sais pas pourquoi la downvote, mais vous avez oublié le g à la fin de la dernière ligne. –

+0

Pourquoi recommandez-vous contre les prototypes? – mleykamp

0

Juste pour la variété:

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

grep agit comme un filtre sur les listes. C'est pourquoi les \s+ doivent être remplacés par \s* dans l'expression rationnelle. Forcer des correspondances sur 0 ou plusieurs espaces empêche grep de filtrer les éléments de la liste qui n'ont pas d'espaces de début ou de fin.

+0

Mais cela n'inclurait pas les segments entourés de tabulations sans espace. '" \ tspoon \ t "' serait omis. – Axeman

+0

@Axeman: De ['perlretut'] (http://perldoc.perl.org/perlretut.html):" '\ s' correspond à un caractère d'espace, l'ensemble' [\ \ t \ r \ n \ f] 'et d'autres." D'ailleurs, ne nous séparons-nous pas sur \ t' ici;)? – Zaid

+0

oui - mais cela ne fait rien, mes yeux ont remplacé '\ s *' par mon habituel '\ s +'. Donc le subst correspond toujours et je ne sais pas de quoi je parle. : D – Axeman

1

Vous pouvez également utiliser "foreach" ici.

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

Lorsque je coupe une chaîne, je ne souhaite pas souvent conserver l'original. Ce serait bien d'avoir l'abstraction d'un sous-marin mais aussi de ne pas avoir à se soucier des valeurs temporaires.

Il se avère que nous pouvons faire tout cela, comme perlsub explique:

Tous les arguments passés dans le show dans le tableau @_. Par conséquent, si vous appelez une fonction avec deux arguments, ceux-ci seront stockés dans $_[0] et $_[1]. Le tableau @_ est un tableau local, mais ses éléments sont des alias pour les paramètres scalaires réels. En particulier, si un élément $_[0] est mis à jour, l'argument correspondant est mis à jour (ou une erreur se produit s'il n'est pas modifiable).

Dans votre cas, trim devient

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

Rappelez-vous que map et for sont des cousins, donc avec la boucle trim, on n'a plus besoin map. Par exemple

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

Sortie:

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

Pourriez-vous expliquer l'utilisation '=>' de la jointure? Je n'ai jamais vu ça auparavant? – mleykamp

+1

@ 10rd_n3r0, je vais y aller, le premier paramètre dans join est spécial, et les autres sont tous traités de la même manière, la "grosse virgule" ('=>') donne juste une meilleure séparation visuelle que ' , '. Je l'ai utilisé moi-même pour cette raison. Comme dans ce cas 'keyword => qw ' rien ne les différencie dans la liste créée, mais je montre la façon dont je pense à eux. J'utilise si pour ces moments-là, je veux que la séparation visuelle dépeigne la sémantique. – Axeman

+0

@ 10rd Je l'ai utilisé pour la séparation visuelle comme @Axeman décrit. Au moment où je l'écrivais, j'avais à l'origine 'join (", "=> ...)', et chaque fois que le séparateur contient une virgule, j'aime utiliser la grosse virgule pour la lisibilité. –