In Perl kann ich:
my ($x, $y) = split /:/, $str;
Und es wird funktionieren, ob die Zeichenfolge das Muster enthält oder nicht.
In Python funktioniert dies jedoch nicht:
a, b = "foo".split(":") # ValueError: not enough values to unpack
Was ist der kanonische Weg, um Fehler in solchen Fällen zu vermeiden?
python
string
python-3.x
split
planetp
quelle
quelle
$x
und$y
erhalten Sie in Perl, wenn die Zeichenfolge das Muster nicht enthält? Werden beiden die gesamte Zeichenfolge zugewiesen oder wird$y
null oder so?$x
den gesamten String ab,$y
istundef
(ähnlichNone
, aber subtil unterschiedlich).split
Funktion. Es scheint auch, dass Perl'ssplit
einen regulären Ausdruck akzeptiert.split
ist näher dran,re.split
außer dass es zusätzliche Magie für Leerzeichen gibt.Antworten:
Wenn Sie sich in nur zwei Teile aufteilen (wie in Ihrem Beispiel), können
str.partition()
Sie ein garantiertes Argument erhalten, das die Größe 3 entpackt:>>> a, sep, b = 'foo'.partition(':') >>> a, sep, b ('foo', '', '')
str.partition()
Gibt immer ein 3-Tupel zurück, unabhängig davon, ob das Trennzeichen gefunden wurde oder nicht.Eine andere Alternative für Python 3.x ist das erweiterte iterierbare Entpacken :
>>> a, *b = 'foo'.split(':') >>> a, b ('foo', [])
Dadurch wird das erste geteilte Element
a
und die Liste der verbleibenden Elemente (falls vorhanden) zugewiesenb
.quelle
Da Sie auf Python 3 sind, ist es einfach. PEP 3132 führte eine willkommene Vereinfachung der Syntax beim Zuweisen zu Tupeln ein - Erweitertes iterierbares Entpacken . In der Vergangenheit muss bei der Zuweisung zu Variablen in einem Tupel die Anzahl der Elemente links von der Zuweisung genau der Anzahl rechts entsprechen.
In Python 3 können wir jede Variable auf der linken Seite als Liste festlegen, indem wir ein Sternchen * voranstellen. Dadurch werden so viele Werte wie möglich erfasst, während die Variablen rechts davon ausgefüllt werden (es muss also nicht das Element ganz rechts sein). Dies vermeidet viele böse Scheiben, wenn wir die Länge eines Tupels nicht kennen.
a, *b = "foo".split(":") print("a:", a, "b:", b)
Gibt:
BEARBEITEN Sie folgende Kommentare und Diskussionen:
Im Vergleich zur Perl-Version ist dies erheblich anders, aber es ist die Python (3) -Methode. Im Vergleich zur Perl-Version
re.split()
wäre dies ähnlicher, jedoch ist das Aufrufen der RE-Engine zum Aufteilen um ein einzelnes Zeichen ein unnötiger Aufwand.Mit mehreren Elementen in Python:
s = 'hello:world:sailor' a, *b = s.split(":") print("a:", a, "b:", b)
gibt:
a: hello b: ['world', 'sailor']
Jedoch in Perl:
my $s = 'hello:world:sailor'; my ($a, $b) = split /:/, $s; print "a: $a b: $b\n";
gibt:
Es ist ersichtlich, dass zusätzliche Elemente in Perl ignoriert werden oder verloren gehen. Das ist bei Bedarf in Python ziemlich einfach zu replizieren:
s = 'hello:world:sailor' a, *b = s.split(":") b = b[0] print("a:", a, "b:", b)
Also,
a, *b = s.split(":")
Äquivalent in Perl wäreNB: Wir sollten verwenden nicht
$a
und$b
im Allgemeinen Perl , da sie eine besondere Bedeutung haben , wenn verwendet mitsort
. Ich habe sie hier verwendet, um die Konsistenz mit dem Python-Beispiel zu gewährleisten.Python hat einen zusätzlichen Trick im Ärmel, wir können zu jedem Element im Tupel auf der linken Seite entpacken:
s = "one:two:three:four" a, *b, c = s.split(':') print("a:", a, "b:", b, "c:", c)
Gibt:
a: one b: ['two', 'three'] c: four
Während in der äquivalenten Perl, das Array (
@b
IS) gierig, und die skalare$c
istundef
:use strict; use warnings; my $s = 'one:two:three:four'; my ($a, @b, $c) = split /:/, $s; print "a: $a b: @b c: $c\n";
Gibt:
Use of uninitialized value $c in concatenation (.) or string at gash.pl line 8. a: one b: two three four c:
quelle
b
?a,*b,c = "foo:bar:baz:last".split(":")
gibta="foo"
b=["bar","baz"]
c="last"
EDIT: Es wird sterben, wenn Sie es nicht genug Werte für die bestimmten Dinge geben, dh die gleiche Aussage mit"foo"
geteilt wirdValueError: not enough values to unpack (expected at least 2, got 1)
str.partition
führt nur einen Split durch. Es ist also wie vorbeimaxsplit=1
.split()
zwei Skalaren zuweisen, erhalten Sie entweder zwei Zeichenfolgen oder eine Zeichenfolge und eineundef
, aber niemals eine Zeichenfolge und eine Array-Referenz.Sie können die Ausnahme jederzeit abfangen.
Zum Beispiel:
some_string = "foo" try: a, b = some_string.split(":") except ValueError: a = some_string b = ""
Wenn das Zuweisen der gesamten ursprünglichen Zeichenfolge
a
und einer leeren Zeichenfolgeb
das gewünschte Verhalten ist, würde ich wahrscheinlich verwenden,str.partition()
wie es eugene y vorschlägt. Mit dieser Lösung haben Sie jedoch mehr Kontrolle darüber, was genau passiert, wenn die Zeichenfolge kein Trennzeichen enthält. Dies kann in einigen Fällen hilfreich sein.quelle
'a:b:c:d:e'
split
gibt immer eine Liste zurück.a, b = ...
erwartet immer eine Listenlänge von zwei. Sie können so etwas wie verwendenl = string.split(':'); a = l[0]; ...
.Hier ist ein Einzeiler:
a, b = (string.split(':') + [None]*2)[:2]
quelle
Wie wäre es mit regulären Ausdrücken:
import re string = 'one:two:three:four'
in 3.X:
a, *b = re.split(':', string)
in 2.X:
a, b = re.split(':', string)[0], re.split(':', string)[1:]
Auf diese Weise können Sie auch reguläre Ausdrücke zum Teilen verwenden (dh \ d).
quelle