我的输入是:
input = ['(var1, )', '(var2,var3)']
预期输出为:
output = [('var1', ), ('var2','var3')]
迭代输入并在元组字符串上使用eval
/ literal_eval
是不可能的:
>>> eval('(var1, )')
>>> NameError: name 'var1' is not defined
如何将'(var1, )'
之类的项目转换为内部对象被视为字符串而不是变量的元组?
是否有比编写解析器或使用正则表达式更简单的方法?
答案 0 :(得分:12)
对于每次出现的变量,eval
在符号表中搜索变量的名称。可以提供自定义映射,该映射将返回每个缺失键的键名称:
class FakeNamespace(dict):
def __missing__(self, key):
return key
示例:
In [38]: eval('(var1,)', FakeNamespace())
Out[38]: ('var1',)
In [39]: eval('(var2, var3)', FakeNamespace())
Out[39]: ('var2', 'var3')
注意: eval
将当前全局变量复制到提交的globals
字典,如果它没有__builtins__
。这意味着表达式可以访问内置函数,异常和常量,以及命名空间中的变量。您可以尝试通过传递FakeNamespace(__builtins__=<None or some other value>)
而非FakeNamespace()
来解决此问题,但不会使eval
100%安全(Python eval: is it still dangerous if I disable builtins and attribute access?)
答案 1 :(得分:5)
试试这个:
tuples = [tuple(filter(None, t.strip('()').strip().split(','))) for t in input]
例如:
In [16]: tuples = [tuple(filter(None, t.strip('()').strip().split(','))) for t in input]
In [17]: tuples
Out[17]: [('var1',), ('var2', 'var3')]
我们正在遍历我们的元组字符串列表,并为每个字符串删除()
,然后将{1}}将字符串拆分为列表,然后将列表转换回一个元组。我们使用filter()
删除空元素。
答案 2 :(得分:4)
我喜欢vaultah的解决方案。如果ast.literal_eval
不是选项,那么另一个re
和eval
:
>>> import re
>>> from ast import literal_eval
>>> [literal_eval(re.sub('(?<=\(|,)(\w+)(?=\)|,)', r'"\1"', x)) for x in input]
[('var1',), ('var2', 'var3')]