2016-07-01 68 views
73

In Perl posso fare:Come dividere in modo affidabile una stringa in Python?

my ($x, $y) = split /:/, $str; 

e funzionerà o meno la stringa contiene il modello.

In Python, tuttavia questo non funziona:

a, b = "foo".split(":") # ValueError: not enough values to unpack 

Qual è il modo canonico per evitare errori in questi casi?

+4

In Perl, cosa significa '$ x' e '$ y' get se la stringa non contiene il pattern? Ad entrambi viene assegnata l'intera stringa, oppure '$ y' ottiene nulla o qualcosa? –

+5

@ Don'tPanic: '$ x' ottiene l'intera stringa,' $ y' è 'undef' (che è simile a' None', ma leggermente differente). – cdarke

+0

Qual è il comportamento previsto quando contengono più istanze del modello diviso? Inoltre, l'argomento pattern in Perl 'divide' una regex o una stringa regolare? – jpmc26

risposta

107

se si sta dividendo in due soli pezzi (come nel tuo esempio) è possibile utilizzare str.partition() per ottenere un argomento disimballaggio dimensioni garantito di 3:

>>> a, sep, b = "foo".partition(":") 
>>> a, sep, b 
('foo', '', '') 

str.partition() sempre restituisce una tupla di 3 elementi, se il il separatore è trovato o no.

Un'altra alternativa a Python 3 è di uso prolungato disimballaggio, come descritto in @cdarke's answer:

>>> a, *b = "foo".split(":") 
>>> a, b 
('foo', []) 

Questo assegna il primo elemento di divisione per a e l'elenco degli elementi rimanenti (se presente) per b.

+11

Scrivo Python da anni. ANNI. E questa è la prima volta che vedo un disimballaggio esteso. Questa lingua è assolutamente enorme. – 2rs2ts

60

Dato che siete su Python 3, è facile. PEP 3132 ha introdotto una gradita semplificazione della sintassi durante l'assegnazione alle tuple - Esteso disimballaggio iterabile. In passato, se si assegna a variabili in una tupla, il numero di elementi a sinistra del compito deve essere esattamente uguale a quello a destra.

In Python 3 possiamo designare qualsiasi variabile a sinistra come una lista precedendo con un asterisco *. Questo catturerà quanti più valori possibile, mentre continua a compilare le variabili alla sua destra (quindi non deve essere l'elemento più a destra). Questo evita molte fette sgradevoli quando non conosciamo la lunghezza di una tupla.

a, *b = "foo".split(":") 
print("a:", a, "b:", b) 

Dà:

a: foo b: [] 

EDIT commenti e discussione:

Rispetto alla versione di Perl, questo è molto diverso, ma è il Python (3) modo. In confronto con la versione Perl, re.split() sarebbe più simile, tuttavia il richiamo del motore RE per la divisione attorno a un singolo carattere è un sovraccarico non necessario.

Con gli elementi più in Python:

s = 'hello:world:sailor' 
a, *b = s.split(":") 
print("a:", a, "b:", b) 

dà:

a: hello b: ['world', 'sailor'] 

Tuttavia in Perl:

my $s = 'hello:world:sailor'; 
my ($a, $b) = split /:/, $s; 
print "a: $a b: $b\n"; 

dà:

a: hello b: world 

Si può vedere che gli elementi aggiuntivi vengono ignorati o persi in Perl.Questo è abbastanza facile da replicare in Python se necessario:

s = 'hello:world:sailor' 
a, *b = s.split(":") 
b = b[0] 
print("a:", a, "b:", b) 

Quindi, a, *b = s.split(":") equivalente in Perl sarebbe

my ($a, @b) = split /:/, $s; 

NB: non dovremmo usare $a e $b in generale Perl dal momento che hanno un significato speciale se usato con sort. Li ho usati qui per coerenza con l'esempio di Python.

Python ha un trucco in più nella manica, siamo in grado di decomprimere a qualsiasi elemento nella tupla a sinistra:

s = "one:two:three:four" 
a, *b, c = s.split(':') 
print("a:", a, "b:", b, "c:", c) 

Dà:

a: one b: ['two', 'three'] c: four 

considerando che l'equivalente Perl, il array (@b) è avido, e lo scalare $c è undef:

use strict; 
use warnings; 

my $s = 'one:two:three:four'; 
my ($a, @b, $c) = split /:/, $s; 
print "a: $a b: @b c: $c\n"; 

Dà:

Use of uninitialized value $c in concatenation (.) or string at gash.pl line 8. 
a: one b: two three four c: 
+0

Come funziona se metti una variabile a destra di 'b'? – Panzercrisis

+3

@Panzercrisis è robusto - 'a, * b, c =" pippo: bar: baz: last ".split (": ")' restituisce 'a =" foo "' 'b = [" bar "," baz " ] '' c = "last" 'EDIT: Morirà se non gli dai valori sufficienti per le cose definite, cioè la stessa istruzione con' "foo" 'essendo split' ValueError: non ci sono abbastanza valori da decomprimere (atteso almeno 2, ottenuto 1) ' – Delioth

+1

@magu_ Fa una cosa diversa. 'str.partition' esegue solo * uno * split. Quindi è come passare 'maxsplit = 1'. – Bakuriu

17

split sarà sempre restituire un elenco. a, b = ... si aspetta sempre che la lunghezza dell'elenco sia due. Puoi usare qualcosa come l = string.split(':'); a = l[0]; ....

Ecco un uno di linea: a, b = (string.split(':') + [None]*2)[:2]

22

Tu sei sempre libero di intercettare l'eccezione.

Ad esempio:

some_string = "foo" 

try: 
    a, b = some_string.split(":") 
except ValueError: 
    a = some_string 
    b = "" 

Se assegnando l'intera stringa originale a e una stringa vuota b è il comportamento desiderato, probabilmente uso str.partition() come suggerisce eugene y. Tuttavia, questa soluzione offre un maggiore controllo su ciò che accade quando non c'è alcun separatore nella stringa, che potrebbe essere utile in alcuni casi.

+3

Questo non funzionerebbe se la stringa contenesse * delimitatori multipli *, ad esempio, 'a: b: c: d: e'' – jpmc26

3

ne dite di usare espressioni regolari:

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:] 

In questo modo è anche possibile utilizzare le espressioni regolari per split (cioè \ d)

Problemi correlati