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

har*_*jay 465 python string

我想知道最简单的方法是将string如下列表转换为list:

x = u'[ "A","B","C" , " D"]'
Run Code Online (Sandbox Code Playgroud)

即使用户在逗号和引号内的空格之间放置空格也是如此.我需要处理它:

x = ["A", "B", "C", "D"] 
Run Code Online (Sandbox Code Playgroud)

在Python中.

我知道我可以剥夺的空间与strip()split()使用拆分操作和检查非字母.但是代码变得非常糟糕.有一个我不知道的快速功能吗?

小智 667

>>> 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']
Run Code Online (Sandbox Code Playgroud)

ast.literal_eval:

使用ast.literal_eval,您可以安全地评估表达式节点或包含Python表达式的字符串.提供的字符串或节点可能只包含以下Python文字结构:字符串,数字,元组,列表,dicts,布尔值和None.

  • @PaulKenjora:你在想'eval`,而不是'ast.literal_eval`. (13认同)
  • `ast.literal_eval`是_safer_而不是`eval`,但它实际上不是_safe_.正如[文档的最新版本](https://docs.python.org/3/library/ast.html#ast.literal_eval)解释:"警告可能会使Python解释器崩溃,其中包含足够大/复杂的字符串由于Python的AST编译器中的堆栈深度限制." 事实上,可以通过仔细的堆栈粉碎攻击来运行任意代码,尽管据我所知,没有人为此构建公开的概念证明. (12认同)
  • 根据下面的评论,这很危险,因为它只是运行字符串中的任何python.因此,如果有人拨打电话删除那里的所有内容,那就很乐意. (6认同)
  • @sqp_125,那么它就是一个常规列表,你不需要解析任何东西? (2认同)

Mar*_*ers 74

eval很危险 - 你不应该执行用户输入.

如果你有2.6或更新,使用ast而不是eval:

>>> import ast
>>> ast.literal_eval('["A","B" ,"C" ," D"]')
["A", "B", "C", " D"]
Run Code Online (Sandbox Code Playgroud)

一旦你有了,那strip就是字符串.

如果您使用的是旧版本的Python,则可以使用简单的正则表达式非常接近您想要的内容:

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

这不如ast解决方案,例如它不能正确处理字符串中的转义引号.但它很简单,不涉及危险的评估,并且如果你使用的是较旧的Python,可能对你的目的来说已经足够好了.

  • @AaryanDewan 如果直接使用 `eval`,它将评估任何有效的 python 表达式,这有潜在的危险。`literal_eval` 通过仅评估 Python 文字结构来解决这个问题:字符串、数字、元组、列表、字典、布尔值和 None。 (2认同)

Rya*_*yan 66

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

>>> import json
>>> x = u'[ "A","B","C" , " D"]'
>>> json.loads(x)
[u'A', u'B', u'C', u' D']
Run Code Online (Sandbox Code Playgroud)

同样

>>> x = u'[ "A","B","C" , {"D":"E"}]'
>>> json.loads(x)
[u'A', u'B', u'C', {u'D': u'E'}]
Run Code Online (Sandbox Code Playgroud)

  • 根据@PaulKenjora 的评论,它适用于 `'["a","b"]'` 但不适用于 `"['a','b']"`。 (12认同)
  • 在我的情况下,这适用于整数,但不适用于字符串,因为每个字符串都是单引号而不是双引号。 (4认同)
  • 就我而言,我必须在初始字符串中用双引号替换单引号,以确保它有效 `.replace('\'', '"')` 但我确信该字符串内的数据不包含任何关键的单/其中双引号会影响最终结果。 (2认同)

小智 14

受上述一些与基本 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
Run Code Online (Sandbox Code Playgroud)

方法二: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
Run Code Online (Sandbox Code Playgroud)

方法三:不导入

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
Run Code Online (Sandbox Code Playgroud)

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


tos*_*osh 12

import ast
l = ast.literal_eval('[ "A","B","C" , " D"]')
l = [i.strip() for i in l]
Run Code Online (Sandbox Code Playgroud)


bor*_*ked 12

无需导入任何内容或进行评估。对于大多数基本用例,您可以在一行中完成此操作,包括原始问题中给出的用例。

一班轮

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

解释

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(',')
Run Code Online (Sandbox Code Playgroud)

输出

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
Run Code Online (Sandbox Code Playgroud)

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

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
'''
Run Code Online (Sandbox Code Playgroud)

嵌套列表

如果你有嵌套列表,它确实会变得有点烦人。不使用正则表达式(这会简化替换),并假设你想返回一个扁平列表(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']
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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


小智 10

你可以这样做

**

x = '[ "A","B","C" , " D"]'
print(eval(x))
Run Code Online (Sandbox Code Playgroud)

** 最好的答案是已接受的答案

尽管这不是一种安全的方法,但最好的答案是公认的答案。发布答案时没有意识到评估危险。

  • 在此线程的多个地方不建议使用 eval,因为无论输入什么,它都会简单地作为代码运行,从而存在安全风险。这也是一个重复的答案。 (3认同)

Ale*_*lik 8

有一个快速的解决方案:

x = eval('[ "A","B","C" , " D"]')
Run Code Online (Sandbox Code Playgroud)

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

x = [x.strip() for x in eval('[ "A","B","C" , " D"]')]
Run Code Online (Sandbox Code Playgroud)

  • 这是对任意代码执行的公开邀请,除非您绝对确定输入始终是100%可信的,否则不要执行此操作或类似操作. (16认同)

ruo*_*ola 7

不导入任何内容:

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

  • 警告说明:如果列表中的任何字符串之间有逗号,则可能有潜在的危险。 (6认同)

dir*_*jot 6

假设您的所有输入都是列表,并且输入中的双引号实际上无关紧要,可以使用简单的regexp替换来完成.它有点像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']
Run Code Online (Sandbox Code Playgroud)

junkers变量包含我们不想要的所有字符的编译正则表达式(用于速度),使用]作为字符需要一些反斜杠技巧.re.sub将所有这些字符替换为空,我们将结果字符串拆分为逗号.

请注意,这也会从内部条目u'["oh no"]'---> [u'ohno']中删除空格.如果这不是你想要的,那么regexp需要加强一点.


Pau*_*McG 5

如果您知道您的列表仅包含带引号的字符串,则此 pyparsing 示例将为您提供剥离字符串的列表(甚至保留原始的 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']
Run Code Online (Sandbox Code Playgroud)

如果您的列表可以有更多的数据类型,甚至列表中包含列表,那么您将需要一个更完整的语法 - 就像pyparsing 示例目录中的语法一样,它将处理元组、列表、整数、浮点数和带引号的字符串。