Convertir la représentation de chaîne de liste en liste
Je me demandais quel est le moyen le plus simple de convertir une liste string
comme la suivante en list
:
x = u'[ "A","B","C" , " D"]'
, Même dans le cas où l'utilisateur met des espaces entre les virgules et des espaces à l'intérieur des guillemets. Je dois gérer cela aussi pour:
x = ["A", "B", "C", "D"]
En Python.
Je sais que je peux supprimer des espaces avec strip()
et split()
en utilisant l'opérateur split et vérifier les non alphabets. Mais le code devenait très kludgy. Est-il rapide fonction que je ne suis pas au courant?
12 réponses
>>> import ast
>>> x = u'[ "A","B","C" , " D"]'
>>> x = ast.literal_eval(x)
>>> x
['A', 'B', 'C', ' D']
>>> x = [n.strip() for n in x]
>>> x
['A', 'B', 'C', 'D']
Avec ast.literal_eval, vous pouvez évaluer en toute sécurité un nœud d'expression ou une chaîne contenant une expression Python. La chaîne ou le nœud fourni ne peut consister que des structures littérales Python suivantes: chaînes, nombres, tuples, listes, dicts, booléens et aucun.
Le {[2] } est dangereux - vous ne devriez pas exécuter l'entrée de l'utilisateur.
Si vous avez 2.6 ou plus récent, utilisez ast au lieu de eval:
>>> import ast
>>> ast.literal_eval('["A","B" ,"C" ," D"]')
["A", "B", "C", " D"]
Une Fois que vous avez cela, strip
les cordes.
Si vous utilisez une ancienne version de Python, vous pouvez vous rapprocher de ce que vous voulez avec une simple expression régulière:
>>> x='[ "A", " B", "C","D "]'
>>> re.findall(r'"\s*([^"]*?)\s*"', x)
['A', 'B', 'C', 'D']
Ce n'est pas aussi bon que la solution ast, par exemple, il ne gère pas correctement les guillemets échappés dans les chaînes. Mais c'est simple, n'implique pas une évaluation dangereuse, et pourrait soyez assez bon pour votre but si vous êtes sur un Python plus ancien sans ast.
Le json
le module est une meilleure solution chaque fois qu'il y a une liste de dictionnaires stringified. La fonction json.loads(your_data)
peut être utilisée pour la convertir en liste.
>>> import json
>>> x = u'[ "A","B","C" , " D"]'
>>> json.loads(x)
[u'A', u'B', u'C', u' D']
De même
>>> x = u'[ "A","B","C" , {"D":"E"}]'
>>> json.loads(x)
[u'A', u'B', u'C', {u'D': u'E'}]
import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
Avec numpy
cela fonctionne de manière très simple
x = u'[ "A","B","C" , " D"]'
list_string = str(x)
import numpy as np
print np.array(list_string)
Donne
>>>
[ "A","B","C" , " D"]
En supposant que toutes vos entrées sont des listes et que les guillemets doubles dans l'entrée n'ont pas d'importance, cela peut être fait avec un simple regexp replace. C'est un peu perl-y mais fonctionne comme un charme. Notez également que la sortie est maintenant une liste de chaînes unicode, vous n'avez pas spécifié que vous en aviez besoin, mais cela semble logique étant donné l'entrée unicode.
import re
x = u'[ "A","B","C" , " D"]'
junkers = re.compile('[[" \]]')
result = junkers.sub('', x).split(',')
print result
---> [u'A', u'B', u'C', u'D']
La variable junkers contient une expression rationnelle compilée (pour la vitesse) de tous les caractères que nous ne voulons pas, en utilisant ] comme caractère requis supercherie antislash. Re.sub remplace tous ces caractères par rien, et nous divisons la chaîne résultante aux virgules.
Notez que cela supprime également les espaces des entrées intérieures u'["oh no"] '- - - >[u'Ohno']. Si ce n'est pas ce que vous vouliez, l'expression rationnelle doit être gonflée un peu.
Il y a une solution rapide:
x = eval('[ "A","B","C" , " D"]')
Les espaces non désirés dans les éléments de la liste peuvent être supprimés de cette manière:
x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
Si vous savez que vos listes ne contiennent que des chaînes entre guillemets, cet exemple de pyparsing vous donnera votre liste de chaînes dépouillées(même en préservant L'Unicode D'origine).
>>> from pyparsing import *
>>> x =u'[ "A","B","C" , " D"]'
>>> LBR,RBR = map(Suppress,"[]")
>>> qs = quotedString.setParseAction(removeQuotes, lambda t: t[0].strip())
>>> qsList = LBR + delimitedList(qs) + RBR
>>> print qsList.parseString(x).asList()
[u'A', u'B', u'C', u'D']
Si vos listes peuvent avoir plus de types de données, ou même contenir des listes dans des listes, alors vous aurez besoin d'une grammaire plus complète comme celle - ci sur le wiki pyparsing, qui traitera les tuples, les listes, les ints, les flottants et les chaînes entre guillemets. Fonctionnera avec les versions Python à 2.4.
Pour compléter la réponse de @Ryan en utilisant json, une fonction très pratique pour convertir unicode est celle affichée ici: https://stackoverflow.com/a/13105359/7599285
Ex avec guillemets doubles ou simples:
>print byteify(json.loads(u'[ "A","B","C" , " D"]')
>print byteify(json.loads(u"[ 'A','B','C' , ' D']".replace('\'','"')))
['A', 'B', 'C', ' D']
['A', 'B', 'C', ' D']
Je voudrais fournir une solution de patterning plus intuitive avec regex. La fonction ci-dessous prend comme entrée une liste stringifiée contenant des chaînes arbitraires.
Explication par étapes: Vous supprimez tous les espaces, bracketing et value_separators (à condition qu'ils ne fassent pas partie des valeurs que vous souhaitez extraire, sinon rendre l'expression rationnelle plus complexe). Ensuite, vous divisez la chaîne nettoyée sur des guillemets simples ou doubles et prenez les valeurs non vides (ou les valeurs indexées impaires, quel que soit le préférence).
def parse_strlist(sl):
import re
clean = re.sub("[\[\],\s]","",sl)
splitted = re.split("[\'\"]",clean)
values_only = [s for s in splitted if s != '']
return values_only
Testsample: "['21',"foo" '6', '0', "Un"]"
Donc, en suivant toutes les réponses, j'ai décidé de chronométrer les méthodes les plus courantes:
from time import time
import re
import json
my_str = str(list(range(19)))
print(my_str)
reps = 100000
start = time()
for i in range(0, reps):
re.findall("\w+", my_str)
print("Regex method:\t", (time() - start) / reps)
start = time()
for i in range(0, reps):
json.loads(my_str)
print("json method:\t", (time() - start) / reps)
start = time()
for i in range(0, reps):
ast.literal_eval(my_str)
print("ast method:\t\t", (time() - start) / reps)
start = time()
for i in range(0, reps):
[n.strip() for n in my_str]
print("strip method:\t", (time() - start) / reps)
regex method: 6.391477584838867e-07
json method: 2.535374164581299e-06
ast method: 2.4425282478332518e-05
strip method: 4.983267784118653e-06
Donc à la fin regex gagne!
Sans importer quoi que ce soit;
x = u'[ "A","B","C" , " D"]'
ls = x.strip('][').split(',')