我有一个(大量)列表表示为字符串(不是这样,这只是一个例子)
"['A', 'B', 'C']"
我需要将其设为列表类型:
['A', 'B', 'C']
但如果我这样做:
list("['A', 'B', 'C']")
显然我会得到:
['[', "'", 'A', "'", ',', ' ', "'", 'B', "'", ',', ' ', "'", 'C', "'", ']']
目前我正在使用:
ast.literal_eval("['A', 'B', 'C']")
除了我的程序正在处理的列表很大,字符串是数百万字节(测试字符串超过400万个字符)。所以每当我尝试运行它时,我的ast.literal_eval()都会返回一个MemoryError。
因此,我需要一种方法(它不必是pythonic,优雅甚至特别有效)将这些巨大的字符串放入列表而不返回错误。
答案 0 :(得分:3)
输入数据格式并不完全标准,解析起来不方便,特别是因为它很大。根据数据的来源,您应该开始将其保存在真实数据库中,或者考虑如何使其成为可解析的JSON。例如,如果我们在当前样本输入中用双引号替换单引号,我们可以用json
解析它:
>>> import json
>>> s = "['A', 'B', 'C']"
>>> json.loads(s.replace("'", '"'))
[u'A', u'B', u'C']
然后,一旦数据是JSON,它就是一个不同且更常见的问题。您可以使用增量解析器之一,如ijson
或事件驱动的yajl
,以避免内存错误。
答案 1 :(得分:3)
您可以尝试使用基于迭代器接口和itertools模块的延迟解析。
您可以使用例如itertools.takewhile:
def lazy_to_list(input_string):
iterable = iter(input_string)
next(iterable) # skip [
l = []
while True:
value = ''.join(itertools.takewhile(lambda c: c != ',', iterable))
if not value:
break
if value.endswith("]"):
value = value.rstrip("]")
l.append(eval(value))
return l
N = 1000000
s = repr(list(range(N)))
assert lazy_to_list(s) == list(range(N))
额外的改进是从文件中延迟加载巨大的字符串(因为所有处理都是懒惰的)。显然,它会在对象表示中打破逗号(可能还有更多的原因)。
无论如何,对于定义严重的问题,它仍然是一种解决方案。根据基础数据的类型和外部要求(例如,文件应该是人可读的,而不仅仅是机器),您可以更好地使用标准序列化格式(例如json,xml,{{3}等等。)
答案 2 :(得分:0)
很抱歉浪费你的时间,我尝试了其他一切之后找到了一个非常灵巧但有效的解决方案:
str.split("', '")
并且移除了末端括号,因为任何字符串中都没有因为它的使用方式而突然出现。我们去了。
答案 3 :(得分:0)
你可以使用真棒的YAML库(pip install pyyaml
)。
>>> import yaml
>>> yaml.load("['A', 'B', 'C']")
['A', 'B', 'C']
如果您正在阅读文件,您也可以这样做:
>>> with open(myfile) as fid:
... data = yaml.load(fid)
答案 4 :(得分:-2)
使用Python内置的eval( str )
函数可能会更好运。
eval("['A', 'B', 'C']")
返回一个列表对象
['A', 'B', 'C']
答案 5 :(得分:-2)
>>> import ast
>>> input = "['A', 'B', 'C']"
>>> list = ast.literal_eval(input)
>>> output = [i.strip() for i in list]
>>> type(output)
<class 'list'>
>>> output
['A', 'B', 'C']