2009-08-11 9 views
4

Repost from Perlmonks für einen Mitarbeiter:Wie kann ich Perls Split-Befehl mit Weißraum-Trimmen kombinieren?

Ich schrieb ein Perl-Skript, um lange Listen von E-Mails durch einen Semikolon getrennt zu trennen. Was ich mit dem Code machen möchte, ist die Kombination der Aufteilung mit dem Beschneiden von Leerraum, so dass ich nicht zwei Arrays benötige. Gibt es Weg zu trimmen, während das erste Array geladen wird. Ausgabe ist eine sortierte Liste von Namen. Danke.

#!/pw/prod/svr4/bin/perl 
use warnings; 
use strict; 

my $file_data = 
    'Builder, Bob ;Stein, Franklin MSW; Boop, Elizabeth PHD Cc: Bear, 
+ Izzy'; 
my @email_list; 

$file_data =~ s/CC:/;/ig; 
$file_data =~ s/PHD//ig; 
$file_data =~ s/MSW//ig; 

my @tmp_data = split(/;/, $file_data); 

foreach my $entry (@tmp_data) { 
    $entry =~ s/^[ \t]+|[ \t]+$//g; 
    push(@email_list, $entry); 
} 

foreach my $name (sort(@email_list)) { 
    print "$name \n"; 
} 
+2

Haben Sie versucht: split/\ s *; \ s * /, $ file_data –

+0

Ich denke, Sie könnten auch unpack() verwenden, aber ich kann es jetzt nicht versuchen, und ich grok nicht entpacken() genug um Ihnen ohne sie eine Lösung anzubieten. – Makis

Antwort

10

Sie müssen nicht beide Vorgänge auf einmal mit derselben Funktion ausführen. Manchmal können die einzelnen Aktionen klarer ausgeführt werden. Das heißt, Split zuerst, dann die Leer abzustreifen jedes Elements (und dann das Ergebnis sortieren):

@email_list = 
    sort(
     map { 
       s/\s*(\S+)\s*/\1/; $_ 
      } 
      split ';', $file_data 
    ); 

EDIT: Abisolieren mehr als ein Teil einer Zeichenfolge zur gleichen Zeit zu Gefahren führen kann, z.B. Sinans Punkt unten über das Hinterlassen von Leerzeichen im "Elizabeth" -Teil. Ich habe dieses Snippet mit der Annahme codiert, dass der Name kein internes Whitespace haben würde, was eigentlich völlig falsch ist und sich als falsch herausgestellt hätte, wenn ich es bewusst bemerkt hätte. Der Code wird viel verbessert (und besser lesbar auch) unter:

@email_list = 
    sort(
     map { 
       s/^\s+//; # strip leading spaces 
       s/\s+$//; # strip trailing spaces 
       $_   # return the modified string 
      } 
      split ';', $file_data 
    ); 
+0

Anscheinend kann nicht mehrere Leerzeichen in Kommentaren haben, aber es gibt Leerzeichen nach * Elizabeth *. –

+0

> Erste ... Zweite ... sehr gute Punkte! Bearbeitete Antwort oben. – Ether

+0

+1 Danke für die Korrekturen. –

11

Wenn Sie nicht das erste und letzte Element trimmen müssen, wird dies den Trick:

@email_list = split /\s*;\s*/, $file_data; 

Wenn Sie das erste und letzte Element brauchen zu trimmen, schneiden $file_data erste, dann wiederhole wie oben. :-P

2

Nun, Sie können tun, was Chris vorgeschlagen hat, aber es behandelt keine führenden und abschließenden Leerzeichen in $ file_data.

Sie können Handhabung von diesen wie folgt hinzu:

$file_data =~ s/\A\s+|\s+\z//g; 

Beachten Sie auch, dass zweite Array nicht notwendig war. Überprüfen Sie diese:

my $file_data = 'Builder, Bob ;Stein, Franklin MSW; Boop, Elizabeth PHD Cc: Bear, Izzy'; 
my @email_list; 

$file_data =~ s/CC:/;/ig; 
$file_data =~ s/PHD//ig; 
$file_data =~ s/MSW//ig; 

my @tmp_data = split(/;/, $file_data); 

foreach my $entry (@tmp_data) { 
    $entry =~ s/^[ \t]+|[ \t]+$//g; 
} 

foreach my $name (sort(@tmp_data)) { 
    print "$name \n"; 
} 
-1

Barring einige kleinere sintax Fehler, sollte dies die ganze Arbeit für Sie tun. Oh, Listen Operationen, wie schön du bist!

print join (" \n", sort { $a <=> $b } map { s/^[ \t]+|[ \t]+$//g } split (/;/, $file_data)); 
+1

Mit Map Return ist das Ergebnis von s /// nicht sehr nützlich. Versuchen Sie es mit Karte {s /...// g; $ _} – ysth

+0

Und Sie meinen wahrscheinlich keine numerische Sortierung. – ysth

1
my @email_list = map { s/^[ \t]+|[ \t]+$//g; $_ } split /;/, $file_data; 

oder die elegantere:

use Algorithm::Loops "Filter"; 
my @email_list = Filter { s/^[ \t]+|[ \t]+$//g } split /;/, $file_data; 
0

Jetzt bin ich dran:

my @fields = grep { $_ } split m/\s*(?:;|^|$)\s*/, $record; 

Es streift auch die erste und letzte Elemente auch. Wenn grep ist übertrieben für das erste Element loszuwerden:

my (undef, @fields) = split m/\s*(?:;|^|$)\s*/, $record; 

funktioniert, wenn Sie wissen , dass es ein Raum gibt, aber das ist nicht wahrscheinlich, so

my @fields = split m/\s*(?:;|^|$)\s*/, $record; 
shift @fields unless $fields[0]; 

ist der sicherste Weg, um TU es.

1

Siehe How do I strip blank space from the beginning/end of a string? in den FAQ.

@email_list = sort map { 
    s/^\s+//; s/\s+$//; $_ 
} split ';', $file_data; 

Nun ist auch zu beachten, dass ein Aliasname for Schleifen jedes Element eines Arrays, so

@email_list = sort split ';', $file_data; 

for (@email_list) { 
    s/^\s+//; 
    s/\s+$//; 
} 

würde auch funktionieren.

Verwandte Themen