7
votes

Manière simple de convertir une chaîne en un dictionnaire

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: xxx pré>

au dictionnaire Python suivant: p>

{'name':'John Smith', 'age':34, 'height':173.2, 'location':'US', 'avatar':':,=)'}


0 commentaires

10 Réponses :


4
votes

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}


2 commentaires

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.



-2
votes

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


2 commentaires

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 si vous utilisez la bonne dialecte.



1
votes

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


0 commentaires

9
votes

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)


4 commentaires

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" ou pire avatar = "Âge = 123" . 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



0
votes

Je pense que vous avez juste besoin de définir maxsplit = 1, par exemple, les éléments suivants doivent fonctionner. XXX

EDIT (voir Commentaire):

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


1 commentaires

sa donnez-moi ce {'': ') "" Nom ":" "John Smith",' Âge ':' 34 ',' Hauteur ':' 173.2 ',' Localisation ':' " "',' avatar ':'": '}



2
votes

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
:,=)


0 commentaires

0
votes

faire étape par étape xxx


0 commentaires

1
votes

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


1 commentaires

Si vous allez utiliser eval pourquoi pas simplement faire eval ("dict (" + s + ")") ? Nous n'avons pas besoin de remplacer les substitutions de regex ici lorsque Python soutient déjà cette syntaxe.



1
votes

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}


0 commentaires

3
votes

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


0 commentaires