Jak przekonwertować reprezentację łańcuchową listy na listę?

Zastanawiałem się, jaki jest najprostszy sposób, aby przekonwertować reprezentację łańcuchową listy, taką jak poniżej, na list:

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

Nawet w przypadkach, gdy użytkownik umieszcza spacje między przecinkami i spacjami wewnątrz cudzysłowów, muszę to również obsłużyć i przekonwertować na:

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

Wiem, że mogę usunąć spacje za pomocą strip() i split() i sprawdzić, czy nie ma liter. Ale kod stał się bardzo kludgy. Czy jest jakaś szybka funkcja, o której Nie wiem?

 591
Author: Boris, 2009-12-12

15 answers

>>> import ast
>>> x = '[ "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:

Za pomocą ast.literal_eval możesz bezpiecznie ocenić węzeł wyrażenia lub łańcuch zawierający literał Pythona lub kontener. Podany ciąg znaków lub węzeł może składać się tylko z następujących Literalnych struktur Pythona: ciągów, bajtów, liczb, krotek, list, dictów, booleanów i None.

 842
Author: Boris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-30 08:58:25

The json moduł jest lepszym rozwiązaniem, gdy istnieje stringified lista słowników. Funkcja json.loads(your_data) może być użyta do przekonwertowania jej na listę.

>>> import json
>>> x = '[ "A","B","C" , " D"]'
>>> json.loads(x)
['A', 'B', 'C', ' D']

Podobnie

>>> x = '[ "A","B","C" , {"D":"E"}]'
>>> json.loads(x)
['A', 'B', 'C', {'D': 'E'}]
 108
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-30 09:02:00

The eval jest niebezpieczne - nie powinieneś wykonywać danych wejściowych użytkownika.

Jeśli masz 2.6 lub nowszy, użyj ast zamiast eval:

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

Kiedy już to masz, strip struny.

Jeśli korzystasz ze starszej wersji Pythona, możesz bardzo zbliżyć się do tego, co chcesz, używając prostego wyrażenia regularnego:

>>> x='[  "A",  " B", "C","D "]'
>>> re.findall(r'"\s*([^"]*?)\s*"', x)
['A', 'B', 'C', 'D']

To nie jest tak dobre, jak rozwiązanie ast, na przykład nie obsługuje poprawnie cudzysłowów w łańcuchach. Ale to proste, nie wiąże się z niebezpieczną oceną i może bądź wystarczająco dobry dla swojego celu, jeśli jesteś na starszym Pythonie bez ast.

 84
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 20:21:43
import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
 15
Author: tosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 18:29:02

Jest szybkie rozwiązanie:

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

Niechciane spacje w elementach listy mogą zostać usunięte w ten sposób:

x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
 12
Author: Alexei Sholik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 18:24:11

Zainspirowany niektórymi z powyższych odpowiedzi, które działają z bazowymi pakietami Pythona, porównałem wydajność kilku (używając Pythona 3.7.3):

Metoda 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

Metoda 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

Metoda 3: Brak importu

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

Byłem rozczarowany, widząc, że uznałem metodę o najgorszej czytelności za metodę o najlepszej wydajności... przy wyborze najbardziej czytelnej opcji należy wziąć pod uwagę kompromisy... na Typ obciążeń używam Pythona, ponieważ zwykle cenię czytelność nad nieco bardziej wydajną opcją, ale jak zwykle zależy.

 11
Author: kinzleb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-01 03:54:25

Jeśli jest to tylko lista jednowymiarowa, można to zrobić bez importowania czegokolwiek:

>>> x = u'[ "A","B","C" , " D"]'
>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')
>>> ls
['A', 'B', 'C', 'D']
 11
Author: ruohola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-19 15:58:33

Zakładając, że wszystkie dane wejściowe są listami i że podwójne cudzysłowy w danych wejściowych nie mają znaczenia, można to zrobić za pomocą prostego zastępowania wyrażeń regularnych. Jest trochę perl-y, ale działa jak urok. Zauważ również, że wyjście jest teraz listą ciągów unicode, nie określiłeś, że tego potrzebujesz, ale wydaje się to mieć sens, biorąc pod uwagę wejście 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']

Zmienna junkers zawiera skompilowane Wyrażenie regularne (dla szybkości) wszystkich znaków, których nie chcemy, używając] jako znaku wymaganego sztuczka odwrotnego ukośnika. Re.sub zastępuje wszystkie te znaki niczym, a wynikowy ciąg dzielimy na przecinki.

Zauważ, że usuwa to również spacje z wpisów u ' ["oh no"] '- - - >[u'Ohno']. Jeśli to nie jest to, czego chciałeś, Wyrażenie regularne musi być nieco podrasowane.

 6
Author: dirkjot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 22:18:37

Jeśli wiesz, że Twoje listy zawierają tylko cytowane ciągi znaków, ten przykład pyparsingu da ci listę usuniętych ciągów (nawet zachowując oryginalny Unicode-ness).

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

Jeśli Twoje listy mogą mieć więcej typów danych, a nawet zawierać listy wewnątrz list, będziesz potrzebował pełniejszej gramatyki tej {[5] } na pyparsing wiki, która będzie obsługiwać krotki, listy, ints, pływaki i cytowane ciągi. Będzie współpracować z wersjami Pythona do wersji 2.4.

 4
Author: PaulMcG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-12 21:38:54

Aby uzupełnić odpowiedź @ Ryan za pomocą json, jedną z bardzo wygodnych funkcji do konwersji unicode jest ta zamieszczona tutaj: https://stackoverflow.com/a/13105359/7599285

Ex z podwójnymi lub pojedynczymi cudzysłowami:

>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']
 1
Author: CptHwK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-27 13:56:02

Możesz napotkać taki problem podczas radzenia sobie ze zeskrobanymi danymi przechowywanymi jako ramka danych Pandas.

To rozwiązanie działa jak charm, Jeśli Lista wartości jest obecna jako tekst .

def textToList(hashtags):
    return hashtags.strip('[]').replace('\'', '').replace(' ', '').split(',')

hashtags = "[ 'A','B','C' , ' D']"
hashtags = textToList(hashtags)

Output: ['A', 'B', 'C', 'D']

Nie jest wymagana zewnętrzna biblioteka.

 1
Author: dobydx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-27 18:44:33

Chciałbym zapewnić bardziej intuicyjne rozwiązanie do tworzenia wzorów z regex. Poniższa funkcja przyjmuje jako wejście listę stringified zawierającą dowolne ciągi znaków.

Objaśnienie stopniowe: Usuwasz wszystkie odstępy,bracketing i separatory wartości (pod warunkiem, że nie są one częścią wartości, które chcesz wyodrębnić, w przeciwnym razie regex jest bardziej złożony). Następnie dzielisz oczyszczony ciąg znaków na pojedyncze lub podwójne cudzysłowy i przyjmujesz niepuste wartości (lub nieparzyste wartości indeksowane, niezależnie od preferencje).

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

 0
Author: Jordy Van Landeghem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-01 09:32:00

I z czystym Pythonem - nie importowanie żadnych bibliotek

[x for x in  x.split('[')[1].split(']')[0].split('"')[1:-1] if x not in[',',' , ',', ']]
 0
Author: Ioannis Nasios,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-26 08:40:47

Tak więc, podążając za wszystkimi odpowiedziami postanowiłem zmierzyć się z najczęstszymi metodami:

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

Więc w końcu regex wygrywa!

 -1
Author: passs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-06 11:12:47

/ Align = "left" / strip() fcn po prostu odcinając pierwszy i ostatni znak z reprezentacji łańcuchowej listy (patrz trzecia linia poniżej)

>>> 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'>
 -1
Author: JCMontalbano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-01-08 23:24:24