我在思考如何将以下字符串表示的列表转换为list
的最简单方法:
x = '[ "A","B","C" , " D"]'
即使在用户在逗号之间放置空格,并且在引号内部也放置空格的情况下,我也需要处理并将其转换为:
x = ["A", "B", "C", "D"]
我知道可以使用strip()
和split()
去除空格并检查非字母字符。但是代码变得非常混乱。是否有我不知道的快速函数?
我在思考如何将以下字符串表示的列表转换为list
的最简单方法:
x = '[ "A","B","C" , " D"]'
x = ["A", "B", "C", "D"]
我知道可以使用strip()
和split()
去除空格并检查非字母字符。但是代码变得非常混乱。是否有我不知道的快速函数?
>>> 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
。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']"
。 - Skippy le Grand Gourou.replace('\'', '"')
但我确信该字符串内部的数据不包含任何关键的单/双引号,这些引号会影响最终结果。 - Eugene Chabanovast.literal_eval
方法更加通用。例如,JSON无法处理字符串的b
前缀,因为它不识别单独的bytes
类型。JSON还要求字符串使用双引号。 - Karl Knechteleval
是危险的,你不应该执行用户输入。
如果你有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模块的话,这个方法可能足够好。
eval
很危险,不应该执行用户输入”?我正在使用3.6版本。 - Aaryan Dewaneval
,它将评估任何有效的Python表达式,这可能是危险的。literal_eval
通过仅评估Python文字结构来解决此问题:字符串、数字、元组、列表、字典、布尔值和None。 - Abhishek Menon受到上面一些使用基本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 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
方法三:无需导入
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的工作负载类型,我通常更重视可读性而不是稍微更高效的选项,但这通常取决于具体情况。
有一个快速的解决方案:
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]
>>> x = u'[ "A","B","C" , " D"]'
>>> ls = x.strip('[]').replace('"', '').replace(' ', '').split(',')
>>> ls
['A', 'B', 'C', 'D']
大多数基本用例,包括原始问题中的用例,无需导入任何内容或进行评估即可在一行代码中完成。
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
'[]'
,却得到了 ['']
。如果您正在解析数据框中的列,则可能会出现问题。除此之外,这是一个不错的解决方案! - Ari Anisfeldx.strip('[]').replace('"', '').split(',')
慢。
可能是因为strip操作重复了len(x)次而不是1次,并且创建了两个列表而不是一个(split()
返回的一个和推导式返回的一个)。 - Bananex = '[ "A","B","C" , " D"]'
print(eval(x))
尽管这不是一个安全的方法,但最佳答案是被接受的。 回答发布时没有意识到 eval 的危险。
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']
eval
,而不是ast.literal_eval
。 - user2357112ast.literal_eval
比eval
更安全,但实际上并不是完全安全的。如最近版本的文档中所示:“警告:由于Python的AST编译器中栈深度限制,使用足够大/复杂的字符串可能会导致Python解释器崩溃。” 事实上,通过精心构造的堆栈攻击可能会运行任意代码,尽管据我所知,目前没有人建立公共概念证明。 - abarnert