2012-09-21 13 views
28

Próbuję wykonać podział ciąg na zestawie nieco nieregularnym danych, który wygląda mniej więcej tak:String podzielić na nowej linii, zakładki i pewnej liczby miejsc

\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 

Chciałbym przekonwertować ten w krotkę/dyktaturę, gdzie później podzielę się na dwukropek :, ale najpierw muszę pozbyć się wszystkich dodatkowych białych znaków. Zgaduję, że regex to najlepszy sposób, ale nie mogę znaleźć takiego, który działa, poniżej jest moja próba.

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

Odpowiedz

61

Wystarczy użyć .strip(), usuwa wszystkie spacje dla Ciebie, w tym zakładek i nowych linii, a rozszczepienie. Samo dzielenie można wtedy zrobić z data_string.splitlines():

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

wyjściowa:

>>> [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'] 

Można nawet inline rozszczepianie na : jak teraz:

>>> [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

To działało cudownie, składnia [listy zrozumienie] (http://docs.python.org/tutorial/datastructures.html#list-comprehensions) nie była czymś, co widziałem wcześniej, więc przypuszczam, że " Będę musiał to przeczytać. – PopeJohnPaulII

+0

działa jak urok! niesamowite! dzięki –

0

Można użyć tej

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

można upiec dwie pieczenie na jednym kamieniu regex:

>>> 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 za twoje powiedzenie :) – Yamaneko

+0

Całkiem dobrze, ale twoje '[\ t] *' nic nie robi; '(. +)' zawsze będzie jadło spacje, jeśli takie istnieją. Zamiast tego możesz to zrobić: '(. +?) [\ T] * $'. Niechętny kwantyfikator pozwala mu zatrzymać się wcześniej, a '$' upewnia się, że nadal zużywa całą linię. –

+0

@AlanMoore: poprawny, po edycji. – georg

0

Regex nie są naprawdę najlepsze narzędzie do pracy tutaj. Jak powiedzieli inni, używanie kombinacji str.strip() i str.split() jest drogą do zrobienia. Oto jeden liner to zrobić:

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

Jeśli spojrzeć na the documentation dla str.split:

Jeśli września nie jest określona lub jest None, inny algorytm łupania jest stosowana: przebiegi rzędu spacji są traktowany jako pojedynczy separator, a wynik nie będzie zawierał pustych ciągów na początku lub na końcu, jeśli ciąg ma wiodące lub ciągnące białe znaki. W konsekwencji, rozdzielenie pustego łańcucha lub łańcucha składającego się z białych znaków za pomocą separatora None zwraca [].

Innymi słowy, jeśli próbuje dowiedzieć się, co do przekazania do split dostać '\n\tName: Jane Smith' do ['Name:', 'Jane', 'Smith'], po prostu przekazać nic (lub brak).

To prawie rozwiązuje twój cały problem. Pozostały dwie części.

Po pierwsze, masz tylko dwa pola, z których drugi może zawierać spacje. Więc chcesz tylko jeden podział, nie tak wiele jak to możliwe. A więc:

s.split(None, 1) 

Dalej, masz jeszcze brzydkie dwukropki. Ale nie musisz się na nich rozdzielać.Przynajmniej biorąc pod uwagę dane, które już pokazały nam, jelita grubego pojawia się zawsze pod koniec pierwszego pola, bez spacji i zawsze po przestrzeni, więc można po prostu usunąć go:

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

Istnieje milion oczywiście inne sposoby na to; to tylko ten, który wydaje się najbliższy temu, co już próbowaliście.

Powiązane problemy