2010-03-18 6 views
12

mein $ str = "1: 2: 3: 4: 5"; mein ($ a, $ b) = split (':', $ str, 2);Wie kann ich eine Perl-Zeichenfolge nur beim letzten Vorkommen des Trennzeichens teilen?

In dem obigen Code habe ich Grenze als 2 verwendet, so ein wird $ 1 enthalten und die verbleibenden Elemente in $ b ist. So möchte ich das letzte Element sollte in einer Variablen sein und die Elemente vor dem letzten Element sollte in einer anderen Variablen sein.

Beispiel

$str = "1:2:3:4:5" ; 
# $a should have "1:2:3:4" and $b should have "5" 
$str = "2:3:4:5:3:2:5:5:3:2" 
# $a should have "2:3:4:5:3:2:5:5:3" and $b should have "2" 
+1

Duplizieren: http://stackoverflow.com/questions/1098295/perl-is-there-a-way-to-split-on-the-last-regex -match-only – Zaid

Antwort

16
split(/:([^:]+)$/, $str) 
2

Sie können es Split mit tun und umgekehrt wie folgt:

my $str="1:2:3:4:5"; 
my ($a,$b)=split(':',reverse($str),2); # reverse and split. 

$a = reverse($a); # reverse each piece. 
$b = reverse($b); 

($a,$b) = ($b,$a); # swap a and b 

Jetzt wird $a1:2:3:4 und $b wird 5 sein werden.

Ein viel einfacher und sauberer Weg ist Regex zu verwenden, wie Mark in seiner Antwort getan haben.

+1

Während dies eine Möglichkeit ist, ist es nicht gerade effizient, besonders wenn eine einzelne Zeile das Äquivalent darstellt. Etwas wie 'my ($ a, $ b) = ($ str = ~ /(.*):(.?)/);' – Zaid

7

Sie können auch rindex() verwenden zB

my $str="1:2:3:4:5"; 
$i=rindex($str,":"); 
$a=substr($str,0,$i); 
$b=substr($str,$i+1); 
print "\$a:$a, \$b: $b\n"; 

Ausgang

$ perl perl.pl 
$a:1:2:3:4, $b: 5 
+0

Da das Split-Trennzeichen in diesem Fall so einfach ist, ist dies eine schnellere Lösung als die Verwendung eine Regex zum Analysieren des gesamten Ausdrucks, der versucht, an $ zu binden. – Ether

6

Sie können passende, anstelle von Split:

my ($a,$b) = $str =~ /(.*):(.*)/; 
+0

Ich würde das zweite '. *' Ein '.?' Machen, nur um sicher zu sein. – Zaid

2

Ich weiß, diese Frage ist 4 Jahre alt . Aber ich fand die Antwort von YOU sehr interessant, da ich nicht wusste split könnte so funktionieren. Also möchte ich es mit einem Auszug aus dem perldoc split erweitern, der dieses Verhalten für neue Leser erklärt. :-)

my $str = "1:2:3:4:5"; 
my ($a, $b) = split /:([^:]+)$/, $str; 
# Capturing everything after ':' that is not ':' and until the end of the string 
# Now $a = '1:2:3:4' and $b = '5'; 

Von Perldoc:

Wenn das Muster Gruppen enthält erfassen, dann für jeden Abscheider, ein zusätzliches Feld für jede Teilkette durch eine Gruppe (in der Reihenfolge, in der erfaßt wird, um die erzeugten Gruppen werden gemäß den Rückreferenzen angegeben); Wenn eine Gruppe nicht übereinstimmt, wird der Undef-Wert anstelle einer Teilzeichenfolge erfasst. Beachten Sie außerdem, dass ein solches zusätzliches Feld immer dann erzeugt wird, wenn ein Trennzeichen vorhanden ist (dh immer dann, wenn eine Teilung auftritt), und ein solches zusätzliches Feld wird nicht zum LIMIT gezählt. Betrachten Sie die folgenden Ausdrücke in Listenkontext ausgewertet (jede zurückgegebene Liste wird in dem zugehörigen Kommentar zur Verfügung gestellt):

split(/-|,/, "1-10,20", 3) 
# ('1', '10', '20') 

split(/(-|,)/, "1-10,20", 3) 
# ('1', '-', '10', ',', '20') 

split(/-|(,)/, "1-10,20", 3) 
# ('1', undef, '10', ',', '20') 

split(/(-)|,/, "1-10,20", 3) 
# ('1', '-', '10', undef, '20') 

split(/(-)|(,)/, "1-10,20", 3) 
# ('1', '-', undef, '10', undef, ',', '20') 
0

Ich bin ein bisschen spät auf diese Frage, aber ich habe zusammen eine allgemeinere Lösung:

# Similar to split() except pattern is applied backwards from the end of the string 
# The only exception is that the pattern must be a precompiled regex (i.e. qr/pattern/) 
# Example: 
# rsplit(qr/:/, 'John:Smith:123:ABC', 3) => ('John:Smith', '123', 'ABC') 
sub rsplit { 
    my $pattern = shift(@_); # Precompiled regex pattern (i.e. qr/pattern/) 
    my $expr = shift(@_); # String to split 
    my $limit = shift(@_); # Number of chunks to split into 

    # 1) Reverse the input string 
    # 2) split() it 
    # 3) Reverse split()'s result array element order 
    # 4) Reverse each string within the result array 
    map { scalar reverse($_) } reverse split(/$pattern/, scalar reverse($expr), $limit); 
} 

Es akzeptiert Argumente ähnlich split() mit der Ausnahme, dass das Aufteilen in umgekehrter Reihenfolge erfolgt. Es akzeptiert auch eine Limit-Klausel, falls Sie eine bestimmte Anzahl von Ergebniselementen benötigen.

Hinweis: Dieses Unterprogramm erwartet als ersten Parameter precompiled regex.
Perls split ist ein eingebauter und wird /pat/ korrekt interpretieren, aber der Versuch, /pat/ an ein Unterprogramm zu übergeben, wird als sub($_ =~ /pat/) behandelt.

Dieses Unterprogramm ist nicht kugelsicher! Es funktioniert gut genug für einfache Trennzeichen, aber kompliziertere Muster können Probleme verursachen. Das Muster selbst kann nicht umgekehrt werden, nur der Ausdruck, mit dem es übereinstimmt.


Beispiele:

rsplit(qr/:/, 'One:Two:Three', 2); # => ('One:Two', 'Three') 

rsplit(qr/:+/, 'One:Two::Three:::Four', 3); # => ('One:Two', 'Three', 'Four') 

# Discards leading blank elements just like split() discards trailing blanks 
rsplit(qr/:/, ':::foo:bar:baz'); # => ('foo', 'bar', 'baz') 
Verwandte Themen