web-dev-qa-db-fra.com

Convertir la représentation sous forme de chaîne de liste en liste

Je me demandais quel était le moyen le plus simple de convertir une liste string comme celle-ci en list:

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

Même si l'utilisateur place des espaces entre les virgules et des espaces à l'intérieur des guillemets. Je dois aussi gérer cela pour:

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

en Python.

Je sais que je peux supprimer des espaces avec strip() et split() à l'aide de l'opérateur de division et vérifier l'absence d'alphabets. Mais le code devenait très compliqué. Y at-il une fonction rapide que je ne suis pas au courant?

356
harijay
>>> 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 noeud fourni ne peut contenir que les structures littérales Python suivantes: chaînes, nombres, n-uplets, listes, dicts, booléens et aucun.

557
Roger Pate

La eval est dangereuse - vous ne devez pas exécuter la saisie de l'utilisateur.

Si vous avez 2.6 ou plus récent, utilisez ast à la place de eval:

>>> import ast
>>> ast.literal_eval('["A","B" ,"C" ," D"]')
["A", "B", "C", " D"]

Une fois que vous avez cela, strip les chaînes.

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 des chaînes. Mais c’est simple, n’implique pas une évaluation dangereuse et peut suffire à votre objectif si vous utilisez un Python plus âgé sans ast.

69
Mark Byers

Le module json est une meilleure solution lorsqu'il existe 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'}]
52
Ryan
import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
12
tosh

Il y a une solution rapide:

x = eval('[ "A","B","C" , " D"]')

Les espaces blancs indésirables 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"]')]
7
Alexei Sholik

En supposant que toutes vos entrées soient des listes et que les guillemets dans l'entrée importent peu, vous pouvez le faire en remplaçant une expression rationnelle simple. 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 précisé que vous en aviez besoin, mais cela semble logique de donner une 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, utiliser] comme caractère nécessite une supercherie de barre oblique inversée . 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 un peu améliorée. 

7
dirkjot

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

Si vous savez que vos listes ne contiennent que des chaînes entre guillemets, cet exemple original vous donnera votre liste de chaînes extraites (même en préservant le caractère 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 gérera des n-uplets, des listes, des éléments internes, des caractères flottants et des chaînes entre guillemets. . Travaillera avec les versions de Python à la version 2.4.

3
PaulMcG

Sans rien importer;

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

ls = x.strip('][').split(',')
3
ruohola

Pour compléter la réponse de @Ryan avec json, une fonction très pratique pour convertir unicode est celle publiée ici: https://stackoverflow.com/a/13105359/7599285

ex avec des guillemets simples ou doubles:

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

Alors, après 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
passs

Je voudrais fournir une solution de modélisation plus intuitive avec regex. La fonction ci-dessous prend en entrée une liste structurée contenant des chaînes arbitraires. 

Explication pas à pas: Vous supprimez tous les espaces, le bracketing et les value_separators (à condition qu’ils ne fassent pas partie des valeurs que vous voulez extraire, sinon, la regex devient plus complexe). Ensuite, vous divisez la chaîne nettoyée en guillemets simples ou doubles et prenez les valeurs non vides (ou les valeurs indexées impaires, quelle que soit la 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'," A "]"

1

Supposons que votre chaîne est t_vector = [34, 54, 52, 23] et que vous souhaitez convertir cela en une liste. Vous pouvez utiliser les 2 étapes ci-dessous:

ls = t_vector.strip('][')
t_vector = ls.split(' ')

t_vector contient la liste.

0
Coding bat

Inspiré de certaines des réponses ci-dessus qui fonctionnent avec les paquets Python de base, j'ai comparé les performances de quelques-unes (avec Python 3.7.3):

Méthode 1: ast

import ast
list(map(str.strip, ast.literal_eval(u'[ "A","B","C" , " D"]')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, ast.literal_eval(u'[ \"A\",\"B\",\"C\" , \" D\"]')))", setup='import ast', number=100000)
# 1.292875313000195

Méthode 2: json

import json
list(map(str.strip, json.loads(u'[ "A","B","C" , " D"]')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, json.loads(u'[ \"A\",\"B\",\"C\" , \" D\"]')))", setup='import json', number=100000)
# 0.27833264000014424

Méthode 3: aucune importation

list(map(str.strip, u'[ "A","B","C" , " D"]'.strip('][').replace('"', '').split(',')))
# ['A', 'B', 'C', 'D']

import timeit
timeit.timeit(stmt="list(map(str.strip, u'[ \"A\",\"B\",\"C\" , \" D\"]'.strip('][').replace('\"', '').split(',')))", number=100000)
# 0.12935059100027502

J'ai été déçu de voir ce que je considérais comme la méthode avec la plus mauvaise lisibilité était la méthode avec les meilleures performances ... il y a des compromis à prendre en compte lorsque l'option la plus lisible est utilisée ... pour le type de charges de travail pour lesquelles j'utilise python la lisibilité des valeurs par rapport à une option légèrement plus performante, mais comme d’habitude cela dépend.

0
kinzleb

et avec pure python - n'important aucune bibliothèque

[x for x in  x.split('[')[1].split(']')[0].split('"')[1:-1] if x not in[',',' , ',', ']]
0
Ioannis Nasios

vous pouvez enregistrer vous-même le fichier .strip () fcn en supprimant simplement le premier et le dernier caractères de la représentation sous forme de chaîne de la liste (voir la troisième ligne ci-dessous)

>>> mylist=[1,2,3,4,5,'baloney','alfalfa']
>>> strlist=str(mylist)
['1', ' 2', ' 3', ' 4', ' 5', " 'baloney'", " 'alfalfa'"]
>>> mylistfromstring=(strlist[1:-1].split(', '))
>>> mylistfromstring[3]
'4'
>>> for entry in mylistfromstring:
...     print(entry)
...     type(entry)
... 
1
<class 'str'>
2
<class 'str'>
3
<class 'str'>
4
<class 'str'>
5
<class 'str'>
'baloney'
<class 'str'>
'alfalfa'
<class 'str'>
0
JCMontalbano