web-dev-qa-db-fra.com

Chaîne divisée sur la nouvelle ligne, la tabulation et un certain nombre d'espaces

J'essaie d'effectuer une division de chaîne sur un ensemble de données quelque peu irrégulières qui ressemblent à quelque chose comme:

\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

Je voudrais convertir cela en un tuple/dict où je me séparerai plus tard sur le deux-points :, mais je dois d'abord me débarrasser de tous les espaces supplémentaires. J'imagine qu'une expression rationnelle est la meilleure solution, mais je n'arrive pas à en obtenir une qui fonctionne. Voici ma tentative.

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

Utilisez simplement . Strip () , il supprime tous les espaces pour vous, y compris les onglets et les nouvelles lignes, lors du fractionnement. La scission elle-même peut alors être effectuée avec data_string.splitlines() :

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

Sortie:

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

Vous pouvez même insérer la division sur : aussi bien maintenant:

>>> [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']]
78
Martijn Pieters
>>> 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'}
>>>
7
Joran Beasley

Vous pouvez tuer deux oiseaux avec une pierre de 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')]
>>> 
5
georg

Si vous regardez la documentation pour str.split:

Si sep n'est pas spécifié ou est défini sur None, un algorithme de scission différent est appliqué: les suites d'espaces consécutives sont considérées comme un séparateur unique et le résultat ne contient aucune chaîne vide au début ou à la fin si la chaîne est précédée ou terminée. Par conséquent, le fractionnement d'une chaîne vide ou d'une chaîne composée uniquement d'espaces avec un séparateur Aucun renvoie [].

En d’autres termes, si vous essayez de comprendre ce qu’il faut passer à split pour obtenir '\n\tName: Jane Smith' à ['Name:', 'Jane', 'Smith'], rien ne passe (ou aucun).

Cela résout presque tout votre problème. Il reste deux parties.

Premièrement, vous ne disposez que de deux champs, le second pouvant contenir des espaces. Donc, vous voulez seulement un groupe, pas autant que possible. Alors:

s.split(None, 1)

Ensuite, vous avez toujours ces colons embêtants. Mais vous n'avez pas besoin de vous séparer d'eux. Au moins, compte tenu des données que vous nous avez montrées, les deux points apparaissent toujours à la fin du premier champ, sans espace avant et toujours après, vous pouvez donc simplement les supprimer:

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

Il existe bien sûr un million d'autres moyens de le faire. c'est juste celui qui semble le plus proche de ce que vous essayiez déjà.

3
abarnert

Vous pouvez utiliser ceci

string.strip().split(":")
0
Rakesh

Les regex ne sont pas vraiment le meilleur outil pour le travail ici. Comme d'autres l'ont dit, la combinaison de str.strip() et str.split() est la voie à suivre. Voici un one-liner pour le faire:

>>> 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'}
0
Matthew Adams