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?

302
demandé sur martineau 2009-12-12 21:19:03

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

Ast.literal_eval :

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.

491
répondu Community 2018-02-27 09:10:37

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.

64
répondu Mark Byers 2009-12-12 20:21:43

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'}]
42
répondu Ryan 2016-06-22 10:17:45
import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
11
répondu tosh 2009-12-12 18:29:02

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"]
9
répondu octoback 2013-11-01 10:12:26

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.

7
répondu dirkjot 2009-12-12 22:18:37

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"]')]
6
répondu Alexei Sholik 2009-12-12 18:24:11

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.

3
répondu PaulMcG 2009-12-12 21:38:54

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']
2
répondu CptHwK 2018-04-27 13:56:02

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

1
répondu Jordy Van Landeghem 2018-06-01 09:32:00

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!

1
répondu passs 2018-08-06 11:12:47

Sans importer quoi que ce soit;

x = u'[ "A","B","C" , " D"]'

ls = x.strip('][').split(',')
1
répondu ruohola 2018-08-28 13:02:10