2012-09-21 33 views
28

Estoy tratando de realizar una escisión de cadena en un conjunto de datos un tanto irregular que se ve algo como:Separar una cadena en la nueva línea, pestaña y cierto número de espacios

\n\tName: John Smith 
\n\t Home: Anytown USA 
\n\t Phone: 555-555-555 
\n\t Other Home: Somewhere Else 
\n\t Notes: Other data 
\n\tName: Jane Smith 
\n\t Misc: Data with spaces 

me gustaría convertir este en una tupla/dict donde más tarde se dividirá en los dos puntos :, pero primero necesito deshacerme de todos los espacios en blanco adicionales. Supongo que una expresión regular es la mejor manera pero parece que no puedo obtener una que funcione, a continuación está mi intento.

data_string.split('\n\t *') 

Respuesta

61

Sólo tiene que utilizar .strip(), que elimina todos los espacios en blanco para usted, incluyendo las lengüetas y saltos de línea, mientras que la división. La división en sí y luego se puede hacer con data_string.splitlines():

[s.strip() for s in data_string.splitlines()] 

Salida:

>>> [s.strip() for s in data_string.splitlines()] 
['Name: John Smith', 'Home: Anytown USA', 'Phone: 555-555-555', 'Other Home: Somewhere Else', 'Notes: Other data', 'Name: Jane Smith', 'Misc: Data with spaces'] 

Incluso puede inline la división en : así ahora:

>>> [s.strip().split(': ') for s in data_string.splitlines()] 
[['Name', 'John Smith'], ['Home', 'Anytown USA'], ['Phone', '555-555-555'], ['Other Home', 'Somewhere Else'], ['Notes', 'Other data'], ['Name', 'Jane Smith'], ['Misc', 'Data with spaces']] 
+0

Eso funcionó maravillosamente, la sintaxis de la [Lista de comprensión] (http://docs.python.org/tutorial/datastructures.html#list-comprehensions) no era algo que había visto antes, así que supongo que ' Tendré que leerlo. – PopeJohnPaulII

+0

funciona como un encanto! ¡increíble! gracias –

0

Se puede usar esta

string.strip().split(":") 
5
>>> for line in s.splitlines(): 
...  line = line.strip() 
...  if not line:continue 
...  ary.append(line.split(":")) 
... 
>>> ary 
[['Name', ' John Smith'], ['Home', ' Anytown USA'], ['Misc', ' Data with spaces' 
]] 
>>> dict(ary) 
{'Home': ' Anytown USA', 'Misc': ' Data with spaces', 'Name': ' John Smith'} 
>>> 
5

Se puede matar dos pájaros de piedra de una expresión regular:

>>> r = """ 
... \n\tName: John Smith 
... \n\t Home: Anytown USA 
... \n\t Phone: 555-555-555 
... \n\t Other Home: Somewhere Else 
... \n\t Notes: Other data 
... \n\tName: Jane Smith 
... \n\t Misc: Data with spaces 
... """ 
>>> import re 
>>> print re.findall(r'(\S[^:]+):\s*(.*\S)', r) 
[('Name', 'John Smith'), ('Home', 'Anytown USA'), ('Phone', '555-555-555'), ('Other Home', 'Somewhere Else'), ('Notes', 'Other data'), ('Name', 'Jane Smith'), ('Misc', 'Data with spaces')] 
>>> 
+0

+1 por decir :) – Yamaneko

+0

Bastante bien, pero tu '[\ t] *' no está haciendo nada; el '(. +)' siempre comerá el espacio en blanco final si hay alguno. Podrías hacer esto en su lugar: '(. +?) [\ T] * $'. El cuantificador reacio le permite detenerse temprano, mientras que el '$' asegura que aún consuma toda la línea. –

+0

@ AlanMoore: correcto, publicado. – georg

0

Regex de realidad no son la mejor herramienta para el trabajo aquí. Como han dicho otros, usar una combinación de str.strip() y str.split() es el camino a seguir. He aquí un chiste para hacerlo:

>>> data = '''\n\tName: John Smith 
... \n\t Home: Anytown USA 
... \n\t Phone: 555-555-555 
... \n\t Other Home: Somewhere Else 
... \n\t Notes: Other data 
... \n\tName: Jane Smith 
... \n\t Misc: Data with spaces''' 
>>> {line.strip().split(': ')[0]:line.split(': ')[1] for line in data.splitlines() if line.strip() != ''} 
{'Name': 'Jane Smith', 'Other Home': 'Somewhere Else', 'Notes': 'Other data', 'Misc': 'Data with spaces', 'Phone': '555-555-555', 'Home': 'Anytown USA'} 
3

Si nos fijamos en the documentation para str.split:

Si no se especifica SEP o en su defecto, se aplica un algoritmo de división diferente: carreras de los espacios consecutivos son considerado como un único separador, y el resultado no contendrá cadenas vacías al inicio o al final si la cadena tiene espacios en blanco iniciales o finales. En consecuencia, dividir una cadena vacía o una cadena que consta de solo espacios en blanco con un separador Ninguno devuelve [].

En otras palabras, si usted está tratando de averiguar lo que pase a split para obtener '\n\tName: Jane Smith' a ['Name:', 'Jane', 'Smith'], sólo tiene que pasar nada (o ninguno).

Esto casi resuelve todo tu problema. Quedan dos partes.

En primer lugar, solo tiene dos campos, el segundo de los cuales puede contener espacios. Entonces, solo quieres una división, no la mayor cantidad posible. Por lo tanto:

s.split(None, 1) 

A continuación, todavía tienes esos dos puntos molestos. Pero no necesitas dividirte en ellos.Al menos dado los datos que nos has mostrado, el colon siempre aparece al final del primer campo, sin espacio antes y después siempre hay espacio, por lo que sólo se puede quitar:

key, value = s.split(None, 1) 
key = key[:-1] 

Hay un millón otras formas de hacer esto, por supuesto; este es solo el que parece más cercano a lo que ya estabas probando.

Cuestiones relacionadas