Quel est le moyen le plus simple de convertir une chaîne de mots-clés = valeurs vers un dictionnaire, par exemple la chaîne suivante: au dictionnaire Python suivant: p> {'name':'John Smith', 'age':34, 'height':173.2, 'location':'US', 'avatar':':,=)'}
10 Réponses :
EDIT STRY>: Etant donné que le module csv code> ne traite pas si désiré avec des citations intérieurs em> les champs, il faut un peu plus de travail pour la mettre en œuvre Fonctionnalité: age 34
location US
name John Smith
avatar :,=)
height 173.2
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)',
'height': 173.19999999999999}
En ce qui concerne la solution similaire de Managu, cela ne fonctionne pas si la chaîne de droite contient des virgules (qu'ils font au cas où je travaille).
Vous avez raison == CSV ne comprend pas les citations "au milieu" des champs. Permettez-moi de trouver autre chose et de réparer ma réponse.
Toujours séparé par des virgules? Utilisez le module CSV pour diviser la ligne en parties (non cochées):
import csv import cStringIO parts=csv.reader(cStringIO.StringIO(<string to parse>)).next()
Cela ne fonctionne pas dans le cas où une chaîne du côté droit contient une virgule, par ex. dans l'affaire "Avatar" ci-dessus. Une virgule ne sera présentée que sur la droite si elle est à l'intérieur des citations, alors peut-être que cela peut être pris en compte?
CSV Devrait-il prendre en compte i> si vous utilisez la bonne dialecte.
Le code suivant produit le comportement correct, mais est un peu long! J'ai ajouté un espace dans l'avatar pour montrer qu'elle traite bien des virgules et des espaces et des signes égaux à l'intérieur de la chaîne. Toute suggestion pour la raccourcir?
Cela fonctionne pour moi:
# get all the items
matches = re.findall(r'\w+=".+?"', s) + re.findall(r'\w+=[\d.]+',s)
# partition each match at '='
matches = [m.group().split('=', 1) for m in matches]
# use results to make a dict
d = dict(matches)
Cela fonctionne - il suffit d'ajouter des routines pour convertir les valeurs finales en chaînes / INT, etc., puis éliminer les citations doubles indésirables incluses dans les valeurs.
Très gentil merci! Je savais que les expressions régulières seraient la réponse, je n'ai jamais réussi à apprendre à les utiliser efficacement!
Faites confiance à moi, ils valent l'effort. Trouvez un bon testeur de regex interactif (comme Redemo.py) et faites mouiller vos pieds!
Notez qu'il existe des chaînes qui entraîneront la solution de Regexp ci-dessus pour faire des choses étranges, par exemple avatar = "p = 0" code> ou pire avatar = "Âge = 123" code> . Vous aurez besoin d'une solution basée sur un parser si ceux qui vous inquiètent. BTW Je ne sais pas si vous avez un contrôle sur le format d'entrée, mais JSON est très proche du format d'entrée ci-dessus et il y a des modules dans presque toutes les langues pour analyser. json.org
Je pense que vous avez juste besoin de définir maxsplit = 1, par exemple, les éléments suivants doivent fonctionner. EDIT (voir Commentaire): P> Je n'ai pas remarqué Cela "", "était une valeur sous Avatar, la meilleure approche serait d'échapper", "où que vous génériez des données. Encore mieux serait quelque chose comme Json;). Cependant, comme une alternative à la réégyclette, vous pouvez essayer d'utiliser SHLEX, que je pense produit un code plus propre. p>
sa donnez-moi ce {'': ') "" Nom ":" "John Smith",' Âge ':' 34 ',' Hauteur ':' 173.2 ',' Localisation ':' " "',' avatar ':'": '} code>
Voici une approche plus verbeuse du problème à l'aide de PyparSing. Notez les actions d'analyse qui font la conversion automatique des types des chaînes en intenses ou floattes. Également CoteDstring Class enregistre implicitement les guillemets de la valeur indiquée. Enfin, La classe de dict prend chaque groupe 'Key = Val' dans la liste délimitée par des virgules et attribue Résultats Noms à l'aide des jetons de la clé et de la valeur.
['age', 'location', 'name', 'avatar', 'height']
[('age', 34), ('location', 'US'), ('name', 'John Smith'), ('avatar', ':,=)'), ('height', 173.19999999999999)]
[['name', 'John Smith'], ['age', 34], ['height', 173.19999999999999], ['location', 'US'], ['avatar', ':,=)']]
- age: 34
- avatar: :,=)
- height: 173.2
- location: US
- name: John Smith
{'age': 34, 'height': 173.19999999999999, 'location': 'US', 'avatar': ':,=)', 'name': 'John Smith'}
John Smith
:,=)
faire étape par étape
Voici une approche avec eval code>, je considérais que c'est aussi peu fiable cependant, mais ses œuvres pour votre exemple. >>> import re
>>>
>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>>
>>> eval("{"+re.sub('(\w+)=("[^"]+"|[\d.]+)','"\\1":\\2',s)+"}")
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
>>>
Si vous allez utiliser eval code> pourquoi pas simplement faire eval ("dict (" + s + ")") code>? Nous n'avons pas besoin de remplacer les substitutions de regex ici lorsque Python soutient déjà cette syntaxe.
Voici une version quelque peu plus robuste de la solution REGEGEXP:
>>> s='name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
>>> print dict(handle_keyval(m) for m in keyval_re.finditer(s))
{'age': 34, 'location': 'US', 'name': 'John Smith', 'avatar': ':,=)', 'height': 173.19999999999999}
Je suggérerais une façon paresseuse de le faire.
test_string = 'name="John Smith", age=34, height=173.2, location="US", avatar=":,=)"'
eval("dict({})".format(test_string))