2010-02-04 22 views
75

¿Cuál es el punto de '/segment/segment/'.split('/') que devuelve ['', 'segment', 'segment', '']?¿Por qué se devuelven cadenas vacías en resultados de división()?

Observe los elementos vacíos. Si está dividiendo en un delimitador que está en la posición uno y al final de una cadena, ¿qué valor extra le da la cadena vacía devuelta desde cada extremo?

+1

tengo la misma pregunta y buscó durante mucho tiempo. Ahora entiendo que los resultados vacíos son realmente importantes. Gracias por tu pregunta – Emerald214

+1

Una solución es usar 'strip()' para quitar los caracteres de división iniciales y finales de la cadena antes de dividir: ''/ segment/segment /'. Strip ('/'). Split ('/')' – pkamb

Respuesta

114

str.split complementa str.join, por lo

"/".join(['', 'segment', 'segment', '']) 

le lleva de nuevo la cadena original.

Si las cadenas vacías no estaban allí, la primera y última '/' faltaría después de la join()

+7

Simple, pero responde completamente la pregunta. – orokusaki

+0

Me sorprendió descubrir que las comillas son realmente válidas en Python ... pero, pero ... ¿cómo? [Los documentos] (http://docs.python.org/reference/lexical_analysis.html#string-literals) no parecen mencionar esto. –

+0

@Tim, no tengo idea de cómo llegaron esas cotizaciones allí:/ –

6

¿No estoy seguro de qué tipo de respuesta está buscando? Obtienes tres coincidencias porque tienes tres delimitadores. Si no desea que una vacía, sólo tiene que utilizar:

'/segment/segment/'.strip('/').split('/') 
+3

-1 porque obtienes cuatro coincidencias y no tres, y esto tampoco responde la pregunta. – Roman

+0

+1 para contrarrestar el neg .. Él no dijo que obtendría tres resultados. Dijo "tres coincidencias" para "tres delimitadores", lo cual me suena lógico. No obstante, no obtienes "cuatro coincidencias" de nada. Sin embargo, obtienes "cuatro elementos" en tu resultado. Además, no responde directamente al "por qué", pero proporciona una manera simple de obtener lo que realmente quiere ... lo cual no creo que merezca un voto negativo. Si vas a criticar a alguien (con un voto negativo, nada menos) ¡ten más cuidado! ¡Aclamaciones! 8 ^) – wasatchwizard

+0

@wasatchwizard Gracias por la aclaración. Aprecio la corrección y la recomendación. Lamentablemente, ahora mi voto está bloqueado y no se puede cambiar. – Roman

5

Bueno, le permite saber que había un delimitador de allí. Entonces, ver 4 resultados te deja saber que tienes 3 delimitadores. Esto le da el poder de hacer lo que quiera con esta información, en lugar de dejar que Python suelte los elementos vacíos, y luego hacer que compruebe manualmente los delimitadores iniciales o finales si necesita saberlo.

Ejemplo simple: supongamos que quiere comprobar si hay nombres de archivo absolutos o relativos. De esta forma puede hacerlo todo con la división, sin tener que verificar también cuál es el primer carácter de su nombre de archivo.

+0

+1, gracias hombre. – orokusaki

24

Hay dos puntos principales a considerar aquí:

  • esperando que el resultado de '/segment/segment/'.split('/') a ser igual a ['segment', 'segment'] es razonable, pero entonces esto pierde información. Si split() funcionó de la forma que usted deseaba, si le digo que a.split('/') == ['segment', 'segment'], no puede decirme qué era a.
  • ¿Cuál debería ser el resultado de 'a//b'.split() be? ['a', 'b']?, O ['a', '', 'b']? Es decir, ¿debería split() fusionar delimitadores adyacentes? De ser así, será muy difícil analizar los datos delimitados por un carácter, y algunos de los campos pueden estar vacíos. Estoy bastante seguro de que hay mucha gente que do quiere los valores vacíos en el resultado para el caso anterior!

Al final, todo se reduce a dos cosas:

Consistencia: si tengo n delimitadores, en a, me sale n+1 valores de nuevo después de la split().

Debería ser posible hacer las cosas complejas, y fácil de hacer las cosas simples: si desea ignorar las cadenas vacías como consecuencia de la split(), siempre se puede hacer:

def mysplit(s, delim=None): 
    return [x for x in s.split(delim) if x] 

pero si uno doesn 't desea ignorar los valores vacíos, uno debería poder.

El lenguaje tiene que elegir una definición de split() — Hay demasiados casos de uso diferentes para satisfacer los requisitos de todos como opción predeterminada. Creo que la elección de Python es buena y es la más lógica. (Dicho sea de paso, una de las razones por las que no les gusta de C strtok() se debe a que se fusiona delimitadores adyacentes, lo que es extremadamente difícil de hacer seria de análisis/tokenización con él.)

hay una excepción: a.split() sin argumentos exprime el espacio en blanco consecutivo, pero se puede argumentar que esto es lo correcto en ese caso. Si no desea el comportamiento, siempre puede hacerlo al a.split(' ').

+2

+1, gracias por los detalles. – orokusaki

7

Tener x.split(y) siempre devolverá una lista de 1 + x.count(y) artículos es una regularidad preciosa - como @ gnibbler ya ha señalado que hace split y join inversas exactas una de otra (ya que obviamente deben ser), sino que también mapea con precisión la semántica de todo tipo de registros unidos por delimitadores (como csv líneas de archivos [[neta de problemas de cotización]], líneas de /etc/group en Unix, etc.), permite (como se menciona la respuesta de @Roman) verificaciones fáciles para (por ej.) absoluto vs rutas relativas (en rutas de archivos y URL), y así sucesivamente.

Otra forma de verlo es que no se debe simplemente tirar información fuera de la ventana sin ninguna ganancia. ¿Qué se ganaría al hacer x.split(y) equivalente a x.strip(y).split(y)? Nada, por supuesto, es fácil usar el segundo formulario cuando eso es lo que quieres decir, pero si el primer formulario fue arbitrariamente considerado como el segundo, tendrías mucho trabajo por hacer cuando quieres quieres el primero uno (que está lejos de ser raro, como lo señala el párrafo anterior).

Pero en realidad, pensar en términos de regularidad matemática es la manera más simple y general que puede aprender a diseñar API transitables. Para tomar un ejemplo diferente, es muy importante que para cualquier x y y válido x == x[:y] + x[y:] - que indica inmediatamente por qué un extremo de un corte se debe excluir. Cuanto más simple es la afirmación invariante que puede formular, más probable es que la semántica resultante sea lo que necesita en los usos de la vida real, parte del hecho místico de que las matemáticas son muy útiles para tratar con el universo.

Pruebe la formulación de la invariante para un dialecto en el que split anterior y posterior son delimitadores ... contraejemplo-especial entubado: métodos de cadena tales como isspace no son máximamente sencilla - x.isspace() es equivalente a x and all(c in string.whitespace for c in x) - que tonta líder x and es por eso que a menudo se encuentra codificando not x or x.isspace(), para volver a la simplicidad que debería se han diseñado en los métodos de cadena is... (por lo que una cadena vacía "es" lo que usted quiera, contrario a man-in-the- street horse-sense, tal vez [[sets vacíos, como cero & c, siempre han confundido a la mayoría de las personas ;-)]], pero totalmente conforme a obvio bien refinado math ematical sentido común! -).

+0

+1 para una explicación detallada. Gracias Alex. – orokusaki

16

Más en general, para eliminar cadenas vacías devueltas en split() resultados, es posible que desee mirar la función filter.

Ejemplo:

filter(None, '/segment/segment/'.split('/')) 

vuelve

['segment', 'segment'] 
+1

Gracias por esto, no sé por qué esta respuesta está tan abajo, todo lo demás es algo rudimentario. – Wedge

+0

Si se desea recoger el resultado en una lista en lugar de obtener un objeto de filtro como salida, coloque toda la estructura de filtro en 'list (...)'. –

Cuestiones relacionadas