如何将列表的字符串表示转换为列表

我想知道最简单的方法是将如下列表的字符串表示形式转换为list

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

即使用户在逗号之间放置空格,在引号内放置空格,我也需要处理它并将其转换为:

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

我知道我可以去掉strip()split()的空格并检查非字母字符。但是代码变得非常笨拙。有我不知道的快速功能吗?

608906 次浏览

有一个快速的解决方案:

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

列表元素中不需要的空格可以通过以下方式删除:

x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
import astl = ast.literal_eval('[ "A","B","C" , " D"]')l = [i.strip() for i in l]

eval是危险的-您不应该执行用户输入。

如果您有2.6或更高版本,请使用ast而不是ava:

>>> 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解决方案好,例如它不能正确处理字符串中的转义引号。但它很简单,不涉及危险的评估,如果你使用的是没有ast的旧Python,它可能足以满足你的目的。

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

使用ast.literal_eval,您可以安全地计算包含Python文字或容器显示的表达式节点或字符串。提供的字符串或节点只能由以下Python文字结构组成:字符串、字节、数字、元组、列表、字典、布尔值和None

如果您知道您的列表只包含带引号的字符串,这个pyparsing示例将为您提供剥离字符串的列表(即使保留原始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']

如果你的列表可以有更多的数据类型,甚至在列表中包含列表,那么你需要一个更完整的语法——比如pyparsing示例目录中的这一个,它将处理元组、列表、整数、浮点数和引用的字符串。

假设您的所有输入都是列表,并且输入中的双引号实际上无关紧要,这可以通过简单的regexp替换来完成。它有点perl-y,但它的工作原理很神奇。还要注意,输出现在是Unicode字符串的列表,您没有指定您需要它,但考虑到Unicode输入,它似乎是有意义的。

import rex = 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']中的空格。如果这不是您想要的,则需要将正则表达式增强一点。

只要有链化字典列表,json模块就是更好的解决方案。json.loads(your_data)函数可用于将其转换为列表。

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

同样

>>> x = '[ "A","B","C" , {"D":"E"}]'>>> json.loads(x)['A', 'B', 'C', {'D': 'E'}]

为了进一步使用JSON完成Ryan的回答这个答案中有一个非常方便的转换Unicode的函数。

使用双引号或单引号的示例:

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

我想用regex提供一个更直观的图案化解决方案。下面的函数将包含任意字符串的字符串化列表作为输入。

逐步解释:你删除所有的空白、括号和value_separators(如果它们不是你想要提取的值的一部分,否则会使正则表达式更复杂)。然后你在单引号或双引号上拆分清理后的字符串,并取非空值(或奇数索引值,无论偏好如何)。

def parse_strlist(sl):import reclean = 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"]"

所以,按照所有的答案,我决定用最常见的方法来计时:

from time import timeimport reimport 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-07json method:     2.535374164581299e-06ast method:         2.4425282478332518e-05strip method:     4.983267784118653e-06

所以最终Regex赢了!

如果它只是一维列表,则无需导入任何内容即可完成:

>>> x = u'[ "A","B","C" , " D"]'>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')>>> ls['A', 'B', 'C', 'D']

您可以通过从列表的字符串表示形式中切掉第一个和最后一个字符来保存自己的. Stri()函数(参见下面的第三行):

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

受上面一些使用基本Python包的答案的启发,我比较了一些(使用Python 3.7.3)的性能:

方法1:ast

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

方法二:json

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

方法三:不导入

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

我很失望地看到,我认为易读性最差的方法是性能最好的方法……使用最可读的选项时需要考虑权衡……对于我使用Python的工作负载类型,我通常看重易读性而不是性能稍高的选项,但像往常一样,这取决于情况。

使用纯Python-不导入任何库:

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

在处理存储为Pandas DataFrame的抓取数据时,您可能会遇到此类问题。

这个解决方案像魅力如果值列表以文本形式呈现

def textToList(hashtags):return hashtags.strip('[]').replace('\'', '').replace(' ', '').split(',')
hashtags = "[ 'A','B','C' , ' D']"hashtags = textToList(hashtags)
Output: ['A', 'B', 'C', 'D']

不需要外部库。

这通常发生在将存储为字符串的列表加载到CSV时

如果你有你的列表存储在CSV形式像OP问:

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

以下是如何将其加载回列表:

import csvwith open('YourCSVFile.csv') as csv_file:reader = csv.reader(csv_file, delimiter=',')rows = list(reader)
listItems = rows[0]

listItems现在是列表

不需要导入任何东西或评估。您可以在最基本的用例中的一行中执行此操作,包括原始问题中给出的用例。

一个班轮

l_x = [i.strip() for i in x[1:-1].replace('"',"").split(',')]

补充说明

x = '[ "A","B","C" , " D"]'# String indexing to eliminate the brackets.# Replace, as split will otherwise retain the quotes in the returned list# Split to convert to a listl_x = x[1:-1].replace('"',"").split(',')

产出

for i in range(0, len(l_x)):print(l_x[i])# vvvv output vvvvv'''ABCD'''print(type(l_x)) # out: class 'list'print(len(l_x)) # out: 4

您可以根据需要使用列表理解来解析和清理此列表。

l_x = [i.strip() for i in l_x] # list comprehension to clean upfor i in range(0, len(l_x)):print(l_x[i])# vvvvv output vvvvv'''ABCD'''

嵌套列表

如果你有嵌套列表,它确实会变得更烦人。不使用regex(这会简化替换),并假设你想返回一个扁平化列表(和python的禅说扁平比嵌套好):

x = '[ "A","B","C" , " D", ["E","F","G"]]'l_x = x[1:-1].split(',')l_x = [i.replace(']', '').replace('[', '').replace('"', '').strip() for i in l_x]# returns ['A', 'B', 'C', 'D', 'E', 'F', 'G']

如果你需要保留嵌套列表,它会变得有点难看,但它仍然可以用正则表达式和列表理解来完成:

import re
x = '[ "A","B","C" , " D", "["E","F","G"]","Z", "Y", "["H","I","J"]", "K", "L"]'# Clean it up so the regular expression is simplerx = x.replace('"', '').replace(' ', '')# Look ahead for the bracketed text that signifies nested listl_x = re.split(r',(?=\[[A-Za-z0-9\',]+\])|(?<=\]),', x[1:-1])print(l_x)# Flatten and split the non nested list itemsl_x0 = [item for items in l_x for item in items.split(',') if not '[' in items]# Convert the nested lists to listsl_x1 = [i[1:-1].split(',') for i in l_x if '[' in i]# Add the two listsl_x = l_x0 + l_x1

最后一个解决方案将适用于任何存储为字符串的列表,无论是否嵌套。

这个解决方案比我在前面的答案中读到的一些简单,但它需要匹配列表的所有功能。

x = '[ "A","B","C" , " D"]'[i.strip() for i in x.split('"') if len(i.strip().strip(',').strip(']').strip('['))>0]

输出:

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

你能做到的,

**

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

**最好的一个是接受的答案

虽然这不是一个安全的方法,但最好的答案是公认的。当答案被公布时,他没有意识到这一危险。