¿Cómo divido de forma confiable una cadena en Python, cuando puede que no contenga el patrón o todos los n elementos?

En Perl puedo hacer:

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

Y funcionará si la cadena contiene o no el patrón.

En Python, sin embargo esto no funcionará:

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

¿Cuál es la forma canónica de prevenir errores en tales casos?

Related of "¿Cómo divido de forma confiable una cadena en Python, cuando puede que no contenga el patrón o todos los n elementos?"

Si se divide en solo dos partes (como en su ejemplo), puede usar str.partition() para obtener un argumento garantizado que desempaqueta el tamaño de 3:

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

str.partition() siempre devuelve una tupla de 3, ya sea que se encuentre el separador o no.

Otra alternativa para Python 3.x es usar el desempaquetado iterable extendido :

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

Esto asigna el primer elemento dividido a y la lista de elementos restantes (si los hay) a b .

Ya que estás en Python 3, es fácil. PEP 3132 introdujo una simplificación bienvenida de la syntax al asignarla a tuplas: desempaquetado iterable extendido . En el pasado, si se asignan variables a una tupla, el número de elementos a la izquierda de la asignación debe ser exactamente igual al de la derecha.

En Python 3 podemos designar cualquier variable de la izquierda como una lista prefijando con un asterisco *. Eso capturará tantos valores como pueda, mientras sigue poblando las variables a su derecha (por lo que no es necesario que sea el elemento más a la derecha). Esto evita muchos cortes desagradables cuando no sabemos la longitud de una tupla.

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

Da:

 a: foo b: [] 

EDITAR siguiente comentarios y discusión:

En comparación con la versión de Perl, esto es considerablemente diferente, pero es la forma de Python (3). En comparación con la versión de Perl, re.split() sería más similar, sin embargo, invocar el motor RE para dividir alrededor de un solo carácter es una sobrecarga innecesaria.

Con múltiples elementos en Python:

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

da:

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

Sin embargo en Perl:

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

da:

 a: hello b: world 

Se puede ver que los elementos adicionales se ignoran o se pierden en Perl. Eso es bastante fácil de replicar en Python si es necesario:

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

Entonces, a, *b = s.split(":") equivalente en Perl sería

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

NB: no debemos usar $a y $b en Perl en general, ya que tienen un significado especial cuando se usan con sort . Los he usado aquí por coherencia con el ejemplo de Python.

Python tiene un truco adicional en la manga, podemos desempaquetar cualquier elemento de la tupla de la izquierda:

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

Da:

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

Mientras que en el equivalente de Perl, la matriz ( @b ) es codiciosa, y el escalar $c es undef :

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

Da:

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

Siempre eres libre de atrapar la excepción.

Por ejemplo:

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

Si el comportamiento deseado es asignar la cadena original completa a y una cadena vacía a b , probablemente usaría str.partition() como sugiere str.partition() y. Sin embargo, esta solución le da más control sobre qué sucede exactamente cuando no hay un separador en la cadena, lo que podría ser útil en algunos casos.

split siempre devolverá una lista. a, b = ... siempre esperará que la longitud de la lista sea dos. Puedes usar algo como l = string.split(':'); a = l[0]; ... l = string.split(':'); a = l[0]; ... l = string.split(':'); a = l[0]; ...

Aquí hay un liner: a, b = (string.split(':') + [None]*2)[:2]

¿Qué hay de usar expresiones regulares:

 import re string = 'one:two:three:four' 

en 3.X:

 a, *b = re.split(':', string) 

en 2.X:

 a, b = re.split(':', string)[0], re.split(':', string)[1:] 

De esta manera también puede usar expresiones regulares para dividir (es decir, \ d)