如何将列表的字符串表示形式转换为列表?
Posted
技术标签:
【中文标题】如何将列表的字符串表示形式转换为列表?【英文标题】:How to convert string representation of list to a list? 【发布时间】:2022-01-16 04:01:55 【问题描述】:我想知道最简单的方法是将如下列表的字符串表示形式转换为list
:
x = '[ "A","B","C" , " D"]'
即使用户在逗号之间和引号之间放置空格,我也需要处理它并将其转换为:
x = ["A", "B", "C", "D"]
我知道我可以用strip()
和split()
去除空格并检查非字母字符。但是代码变得非常笨拙。有没有我不知道的快捷功能?
【问题讨论】:
您实际上想要完成什么?可能有比尝试将 Python 列表语法转换为实际列表更好的方法... 你用的是什么版本的 Python? @Nicholas Knight:我正在尝试在遗留应用程序中处理用户输入,其中所有列表都作为带有方括号的 unicode 列表输入。 @Mark Byers,我使用的是 python 2.6,所以 ast.literal 方法效果最好 【参考方案1】:>>> 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
。
【讨论】:
根据下面的评论,这是危险的,因为它只是运行字符串中的任何 python。因此,如果有人打电话删除其中的所有内容,它会很高兴地删除。 @PaulKenjora:你想到的是eval
,而不是ast.literal_eval
。
ast.literal_eval
比eval
更安全,但实际上并不安全。正如recent versions of the docs 解释的那样:“警告由于 Python 的 AST 编译器中的堆栈深度限制,可能会使用足够大/复杂的字符串使 Python 解释器崩溃。”事实上,有可能通过小心的堆栈粉碎攻击来运行任意代码,尽管据我所知,没有人为此建立公开的概念证明。
好吧,但是如果列表没有引号怎么办?例如[B 的 4 个,G 的 1 个]
@sqp_125,那么就是一个普通的列表,不需要解析什么?【参考方案2】:
只要有字符串化 字典列表,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']
【讨论】:
这适用于整数,但不适用于我的情况下的字符串,因为每个字符串都是单引号而不是双引号,叹息。 根据@PaulKenjora 的评论,它适用于'["a","b"]'
,但不适用于"['a','b']"
。
在我的情况下,我必须在初始字符串中用双引号替换单引号以确保它工作 .replace('\'', '"')
但我确信该字符串中的数据不包含任何关键的单引号/双引号它会影响最终结果。
它不适用于这个字符串。有人知道为什么吗? '["car_id": "1", "price": 19527.11, "outlier": false]'
如果用户只输入数字列表,我认为这是阻止恶意用户的最安全方法。【参考方案3】:
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
很危险——你不应该执行用户输入。”吗?我正在使用 3.6
@AaryanDewan 如果您直接使用eval
,它将评估任何有效的python表达式,这有潜在的危险。 literal_eval
通过仅评估 Python 文字结构解决了这个问题:字符串、数字、元组、列表、字典、布尔值和无。【参考方案4】:
有一个快速的解决方案:
x = eval('[ "A","B","C" , " D"]')
可以通过这种方式删除列表元素中不需要的空格:
x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
【讨论】:
这仍然会保留引号内的空格 这是对任意代码执行的公开邀请,除非您绝对确定输入将始终 100% 受信任,否则切勿这样做或类似的事情。 我可以使用这个建议,因为我知道我的数据将始终采用这种格式并且是一项数据处理工作。【参考方案5】:import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
【讨论】:
【参考方案6】:受上述一些与基本 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 的工作负载类型因为我通常重视可读性而不是性能稍高的选项,但像往常一样,这取决于。
【讨论】:
'[ "A","B","C" , " D"]'
前面有一个u
有什么特别的原因吗【参考方案7】:
如果它只是一个一维列表,则无需导入任何内容即可完成:
>>> x = u'[ "A","B","C" , " D"]'
>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')
>>> ls
['A', 'B', 'C', 'D']
【讨论】:
注意事项:如果列表中的任何字符串之间有逗号,这可能会很危险。 如果您的字符串列表是列表列表,这将不起作用【参考方案8】:假设您的所有输入都是列表,并且输入中的双引号实际上并不重要,这可以通过简单的正则表达式替换来完成。它有点 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 将所有这些字符都替换为空,我们在逗号处拆分结果字符串。
请注意,这也会从条目 u'["oh no"]' ---> [u'ohno'] 中删除空格。如果这不是您想要的,则需要对正则表达式进行一些改进。
【讨论】:
【参考方案9】:如果您知道您的列表仅包含带引号的字符串,则此 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 wiki 上的this one,它将处理元组、列表、整数、浮点数和带引号的字符串.将与 Python 版本回到 2.4 一起使用。
【讨论】:
能否告诉我如何使用“parseString().asList()”,如果我有这种字符串:'[“A”,“B”,“C”,[” D"]]',正如您所说,pyparsing 也可以做到这一点。但 o 似乎没有找到正确的方法。 “如果您的列表可以有更多的数据类型,或者甚至在列表中包含列表,那么您将需要更完整的语法” - 请参阅我在回答中提供的链接,以获取将处理嵌套的解析器列表和各种其他数据类型。 Pyparsing 不再托管在 wikispaces 中。parsePythonValue.py
示例现在在 GitHub 上,地址为 github.com/pyparsing/pyparsing/blob/master/examples/…【参考方案10】:
这通常发生在您将存储为字符串的列表加载到 CSV 时
如果您将列表以 CSV 格式存储在 OP 询问的格式中:
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)
给出了列表。每个内部列表都是 csv 列的字符串列表。没有列表的字符串表示开头...
@Tomerikoo 字符串表示的列表完全相同,只是它在文件中。
没有。列表的字符串表示形式是"['1', '2', '3']"
。当您读取带有csv.reader
的csv 文件时,每一行都是['1', '2', '3']
。那是字符串列表。不是列表的字符串表示...
@Tomerikoo 你如何将列表存储在文件中,而不是使用这里的任何方法来恢复它。
好吧,假设 csv 里面确实有 [1, 2, 3]
。假设 csv 行是[1,2,3] 4 5
。用list(reader)
阅读它会得到[["[1,2,3]", "4", "5"], ...]
,然后用rows[0]
会得到["[1,2,3]", "4", "5"]
。再说一次,我不明白这如何回答这个问题......【参考方案11】:
为了使用 json 进一步完成@Ryan 的回答,这里发布的一个非常方便的转换 unicode 的功能是:https://***.com/a/13105359/7599285
ex 加双引号或单引号:
>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']
【讨论】:
【参考方案12】:在处理存储为 Pandas DataFrame 的抓取数据时,您可能会遇到此类问题。
如果值列表以文本形式出现,则此解决方案的效果非常好。
def textToList(hashtags):
return hashtags.strip('[]').replace('\'', '').replace(' ', '').split(',')
hashtags = "[ 'A','B','C' , ' D']"
hashtags = textToList(hashtags)
Output: ['A', 'B', 'C', 'D']
不需要外部库。
【讨论】:
【参考方案13】:不需要导入任何东西,也不需要评估。对于大多数基本用例,包括原始问题中给出的用例,您可以在一行中执行此操作。
一个班轮
l_x = [i.strip() for i in x[1:-1].replace('"',"").split(',')]
说明
x = '[ "A","B","C" , " D"]'
# str indexing to eliminate the brackets
# replace as split will otherwise retain the quotes in returned list
# split to conv to 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
'''
嵌套列表
如果你有嵌套列表,它确实会有点烦人。不使用正则表达式(这将简化替换),并假设您要返回一个扁平列表(和zen of python says flat is better than nested):
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']
如果您需要保留嵌套列表,它会有点难看,但仍然可以通过 re 和列表理解来完成:
import re
x = '[ "A","B","C" , " D", "["E","F","G"]","Z", "Y", "["H","I","J"]", "K", "L"]'
# clean it up so regex 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
最后一个解决方案适用于存储为字符串的任何列表,无论是否嵌套。
【讨论】:
【参考方案14】:我想通过正则表达式提供更直观的模式解决方案。 下面的函数将包含任意字符串的字符串化列表作为输入。
逐步解释: 您删除所有空格、括号和 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
testsample: "['21',"foo" '6', '0', "A"]"
【讨论】:
【参考方案15】:因此,根据所有答案,我决定对最常用的方法进行计时:
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
所以最终正则表达式获胜!
【讨论】:
【参考方案16】:您可以通过从列表的字符串表示中切掉第一个和最后一个字符来保存 .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'>
【讨论】:
【参考方案17】:使用纯 python - 不导入任何库
[x for x in x.split('[')[1].split(']')[0].split('"')[1:-1] if x not in[',',' , ',', ']]
【讨论】:
【参考方案18】:这个解决方案比我上面读到的更简单,但需要匹配列表的所有特征
x = '[ "A","B","C" , " D"]'
[i.strip() for i in x.split('"') if len(i.strip().strip(',').strip(']').strip('['))>0]
['A', 'B', 'C', 'D']
【讨论】:
以上是关于如何将列表的字符串表示形式转换为列表?的主要内容,如果未能解决你的问题,请参考以下文章
将List的String表示形式转换为Dictionary Python
Python:将字符串列表转换为布尔值,其中布尔值以字符串形式存在[重复]
将列表中的所有字符串转换为浮点数。适用于单个列表,但不适用于数据框
R语言unlist函数将复杂数据(list列表dataframe字符串String)对象处理成简单向量vector形式:将包含dataframe和字符串的向量列表转换为单个向量(删除数据名称)