提问人:harijay 提问时间:12/13/2009 最后编辑:ShadowRangerharijay 更新时间:4/26/2023 访问量:700775
如何将列表的字符串表示形式转换为列表
How to convert string representation of list to a list
问:
我想知道最简单的方法是什么,将如下所示的列表的字符串表示形式转换为:list
x = '[ "A","B","C" , " D"]'
即使用户在逗号之间放置空格,在引号内放置空格,我也需要处理并将其转换为:
x = ["A", "B", "C", "D"]
我知道我可以用 和 去掉空格,并检查非字母字符。但是代码变得非常笨拙。有没有我不知道的快速功能?strip()
split()
答:
有一个快速的解决方案:
x = eval('[ "A","B","C" , " D"]')
可以通过以下方式删除列表元素中不需要的空格:
x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
评论
import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
这很危险 - 您不应该执行用户输入。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,如果你使用的是没有 ast 的旧 Python,它可能足以满足你的目的。
评论
eval
eval
literal_eval
>>> 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']
计算表达式节点或仅包含 Python 文本或容器显示的字符串。提供的字符串或节点只能由以下 Python 文字结构组成:字符串、字节、数字、元组、列表、字典、集合、布尔值和 .
None
Ellipsis
这可用于评估包含 Python 值的字符串,而无需自己解析值。它不能计算任意复杂的表达式,例如涉及运算符或索引。
评论
eval
ast.literal_eval
ast.literal_eval
比 更安全,但实际上并不安全。正如最新版本的文档所解释的那样:“警告 由于 Python 的 AST 编译器中的堆栈深度限制,可能会使用足够大/复杂的字符串使 Python 解释器崩溃。事实上,通过仔细的堆栈粉碎攻击来运行任意代码是可能的,尽管据我所知,没有人为此构建公开的概念证明。eval
如果您知道您的列表仅包含带引号的字符串,则此 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 examples 目录中的这个语法一样,它将处理元组、列表、整数、浮点数和带引号的字符串。
假设您的所有输入都是列表,并且输入中的双引号实际上无关紧要,这可以通过简单的正则表达式替换来完成。它有点perl-y,但它就像一个魅力。另请注意,输出现在是 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 将所有这些字符替换为 nothing,我们将生成的字符串拆分为逗号。
请注意,这还会删除条目 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'}]
评论
'["a","b"]'
"['a','b']"
.replace('\'', '"')
ast.literal_eval
b
bytes
为了使用 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']
评论
unicode
我想用正则表达式提供一个更直观的模式化解决方案。 以下函数将包含任意字符串的字符串化列表作为输入。
逐步说明:删除所有空格、括号和value_separators(前提是它们不是要提取的值的一部分,否则会使正则表达式更加复杂)。然后,将清理后的字符串拆分为单引号或双引号,并采用非空值(或奇数索引值,无论首选项如何)。
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“]”
因此,在回答了所有问题之后,我决定对最常见的方法进行计时:
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
所以最终正则表达式赢了!
如果它只是一个一维列表,则可以在不导入任何内容的情况下完成此操作:
>>> x = u'[ "A","B","C" , " D"]'
>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')
>>> ls
['A', 'B', 'C', 'D']
评论
你可以通过从列表的字符串表示中切掉第一个和最后一个字符来节省 .strip() 函数(参见下面的第三行):
>>> 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)的性能:
方法一: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
方法二: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 的工作负载类型,我通常更看重可读性,而不是性能稍高的选项,但像往常一样,这取决于。
评论
u
'[ "A","B","C" , " D"]'
使用纯 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 时,通常会发生这种情况
如果您的列表以 OP 询问的形式存储在 CSV 中:
x = '[ "A","B","C" , " D"]'
以下是将其加载回列表的方法:
import csv
with open('YourCSVFile.csv') as csv_file:
reader = csv.reader(csv_file, delimiter=',')
rows = list(reader)
listItems = rows[0]
listItems
现在是列表
评论
list(reader)
"['1', '2', '3']"
csv.reader
['1', '2', '3']
[1, 2, 3]
[1,2,3] 4 5
list(reader)
[["[1,2,3]", "4", "5"], ...]
rows[0]
["[1,2,3]", "4", "5"]
无需导入任何内容或进行评估。对于大多数基本用例,您可以在一行中执行此操作,包括原始问题中给出的用例。
一个衬垫
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 list
l_x = x[1:-1].replace('"',"").split(',')
输出:
for i in range(0, len(l_x)):
print(l_x[i])
# vvvv output vvvvv
'''
A
B
C
D
'''
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 up
for i in range(0, len(l_x)):
print(l_x[i])
# vvvvv output vvvvv
'''
A
B
C
D
'''
嵌套列表
如果你有嵌套列表,它确实会变得更烦人。不使用正则表达式(这将简化替换),并假设您要返回一个扁平化列表(并且 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 simpler
x = x.replace('"', '').replace(' ', '')
# Look ahead for the bracketed text that signifies nested list
l_x = re.split(r',(?=\[[A-Za-z0-9\',]+\])|(?<=\]),', x[1:-1])
print(l_x)
# Flatten and split the non nested list items
l_x0 = [item for items in l_x for item in items.split(',') if not '[' in items]
# Convert the nested lists to lists
l_x1 = [
i[1:-1].split(',') for i in l_x if '[' in i
]
# Add the two lists
l_x = l_x0 + l_x1
最后一个解决方案将适用于存储为字符串的任何列表,无论是否嵌套。
评论
'[]'
['']
x.strip('[]').replace('"', '').split(',')
这个解决方案比我在之前的答案中读到的一些解决方案更简单,但它需要匹配列表的所有功能。
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(eval(x))
** 最好的一个是公认的答案
虽然这不是一种安全的方法,但最好的答案是公认的。 在发布答案时没有意识到评估危险。
评论
json.loads()
而 From JSON 包是 JavaScript 的等效方式,因此使用 JSON 解决方案来让生活更简单json.dumps()
JSON.parse()
JSON.stringify()
import json
a = '[ "A","B","C" , " D"]'
print(json.loads(a)) #['A', 'B', 'C', ' D']
b = ['A', 'B', 'C', ' D']
print(json.dumps(b)) # '["A", "B", "C", " D"]'
如果您不想导入任何库,这是另一种解决方案:
x = '[ "A","B","C" , " D"]'
def toList(stringList):
stringList = stringList.split('[')[1]# removes "["
stringList = stringList.split(']')[0]# removes "]"
stringList = stringList.split(',')#gets objects in the list
return [text.strip()[1:-1] for text in stringList] #eliminate additional " or ' in the string.
toList(x)
输出:
['A', 'B', 'C', ' D']
此方法的警告是,如果字符串中有逗号,则它不起作用,例如,如果您的输入是
x = '[ "A","B,F","C" , " D"]'
您的输出将是
['A', '', '', 'C', ' D']
这不是你想要的。
下一个:Java 字符串到日期的转换
评论