it-roy-ru.com

Преобразовать строковое представление списка в список

Мне было интересно, как проще всего преобразовать список string, подобный следующему, в list:

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

Даже если пользователь ставит пробелы между запятыми и пробелами внутри кавычек. Я должен справиться с этим, чтобы:

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

в Python.

Я знаю, что могу убрать пробелы с помощью strip() и split(), используя оператор split, и проверять наличие не алфавитов. Но код становился очень грязным. Есть ли быстрая функция, о которой я не знаю?

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 :

С ast.literal_eval вы можете безопасно оценить узел выражения или строку, содержащую выражение Python. Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строк, чисел, кортежей, списков, диктов, логических значений и None.

557
Roger Pate

eval опасен - вы не должны выполнять пользовательский ввод.

Если у вас 2.6 или новее, используйте ast вместо eval:

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

Если у вас есть это, strip строки.

Если вы используете более старую версию Python, вы можете получить очень близко к желаемому с помощью простого регулярного выражения:

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

Это не так хорошо, как решение ast, например, оно неправильно обрабатывает экранированные кавычки в строках. Но это просто, не требует опасного eval и может быть достаточно для вашей цели, если вы на старом Python без ast.

69
Mark Byers

Модуль json является лучшим решением, когда существует список словарей stringified. Функцию json.loads(your_data) можно использовать для преобразования ее в список.

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

Так же 

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

Есть быстрое решение:

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

Нежелательные пробелы в элементах списка могут быть удалены следующим образом:

x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
7
Alexei Sholik

Предполагая, что все ваши входные данные являются списками и что двойные кавычки на входе фактически не имеют значения, это можно сделать с помощью простой замены регулярного выражения. Это немного Perl-у, но работает как шарм. Также обратите внимание, что вывод теперь представляет собой список строк в кодировке Unicode, вы не указали, что вам это нужно, но, похоже, это имеет смысл, учитывая ввод в кодировке 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']

Переменная junkers содержит скомпилированное регулярное выражение (для скорости) всех символов, которые нам не нужны, для использования] в качестве символа требуется некоторая хитрость с обратной косой чертой . Re.sub заменяет все эти символы ничем, и мы разделяем полученную строку на запятых. 

Обратите внимание, что при этом также удаляются пробелы внутри записей u '["oh no"]' ---> [u'ohno ']. Если это не то, что вы хотели, регулярное выражение нужно немного улучшить. 

7
dirkjot

с numpy это работает очень простым способом

x = u'[ "A","B","C" , " D"]'
list_string = str(x)
import numpy as np
print np.array(list_string)

дает

>>> 
[ "A","B","C" , " D"]
6
octoback

Если вы знаете, что ваши списки содержат только строки в кавычках, этот пример разбора предоставит вам список разделенных строк (даже сохранив исходную Unicode-ность).

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

Если ваши списки могут иметь больше типов данных или даже содержать списки в списках, то вам понадобится более полная грамматика - например, эта на вики с pyparsing, которая будет обрабатывать кортежи, списки, целые числа, числа с плавающей запятой и строки в кавычках , Будет работать с версиями Python до 2.4.

3
PaulMcG

Ничего не импортируя;

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

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

Чтобы в дальнейшем завершить ответ @Ryan, используя json, одна очень удобная функция для преобразования юникода - это та, которая размещена здесь: https://stackoverflow.com/a/13105359/7599285

например, с двойными или одинарными кавычками:

>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

Итак, следуя всем ответам, я решил выбрать наиболее распространенные методы:

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

Итак, в конце концов, регулярное выражение побеждает!

1
passs

Я хотел бы предоставить более интуитивное решение для создания паттернов с помощью регулярных выражений. Следующая функция принимает в качестве входных данных строковый список, содержащий произвольные строки. 

Пошаговое объяснение: Вы удаляете все пробелы, скобки и разделители-значения (если они не являются частью значений, которые вы хотите извлечь, в противном случае регулярное выражение становится более сложным). Затем вы разбиваете очищенную строку на одинарные или двойные кавычки и принимаете непустые значения (или нечетные индексированные значения, независимо от предпочтений). 

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

тестовый образец : "['21'," foo "'6', '0'," A "]"

1
Jordy Van Landeghem

Давайте предположим, что ваша строка t_vector = [34, 54, 52, 23] и вы хотите преобразовать ее в список. Вы можете использовать следующие 2 шага:

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

t_vector содержит список.

0
Coding bat

Вдохновленный некоторыми ответами выше, что работа с базовыми пакетами Python, я сравнил производительность нескольких (используя Python 3.7.3):

Метод 1: аст

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

Метод 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

Метод 3: нет импорта

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

Я был разочарован, когда увидел, что метод с наихудшей читаемостью - это метод с наилучшей производительностью ... при выборе наиболее удобочитаемой опции нужно учитывать компромиссы ... для типов рабочих нагрузок, для которых я обычно использую python Значение читабельности по сравнению с чуть более производительным вариантом, но, как обычно, зависит.

0
kinzleb

вы можете сохранить себя .strip () fcn, просто вырезав первый и последний символы из строкового представления списка (см. третью строку ниже)

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