【问题标题】:How to convert a string of a tuple into a list in python?如何将元组的字符串转换为python中的列表?
【发布时间】:2014-04-22 05:55:58
【问题描述】:

所以标题听起来很奇怪,因为也许我的问题很奇怪......我有一个 .txt 文件,其中包含来自不同程序的数千行机器输出,格式如下:

candidates(6,1,0,5,[ev(-1000,'C0009814','Stenosis','Acquired stenosis',[stenosis],[patf])])

本质上,我们有'candidates'标记一个元组的开始,'ev'标记单个元素列表中第二个元组的开始。当我从文件中将所有这些读入 python 时,它会作为字符串读入。但我需要一个对象,这样我就可以访问元组的第 n 个索引。真的,我很高兴能找到一种方法来始终从该字符串中获取 ev() 元组的最后一个值,在本例中为 'patf'。

我曾考虑只在 ',' 上进行拆分,但这并不总是成功,因为列表 '[stenosis]' 中的列表有时可能具有像 '[regurgitation, aortic]' 这样的值。额外的 ',' 将列表索引抛出 1,因此它返回 'aortic]' 而不是 '[patf]'。

如果我可以澄清任何事情,或者我是否认为某些知识是理所当然的,在解决这个问题之前需要说出来,请告诉我。非常感谢。我还包括了下面的第二个示例,它说明了拆分“,”的问题。

candidates(8,1,0,7,[ev(-875,'C0003501','Aortic Valve','Aortic valve structure',[aortic,valve],[bpoc])])

编辑:我猜这个对象不需要是一个列表。相同格式的元组效果很好。只要我能始终如一地引用一个索引来获取我需要的信息。谢谢!

编辑 2:我使用 python 2.7.6

【问题讨论】:

    标签: python string list file


    【解决方案1】:

    如果您的数据始终采用相同的格式,最快的方法是使用正则表达式(模块re),如果您知道如何使用的话。

    否则,这是一个非常难看的 hack,您可以尝试使用 eval“解析”数据。这是一个例子:

    eval_globals = {
        "candidates": lambda *args: args,
        "ev": lambda *args: args,
        "aortic": "aortic",
        "valve": "valve",
        "bpoc": "bpoc",
        # Add more of the keywords you need here
    }
    result = eval(line, eval_globals)        
    

    【讨论】:

    • 我将研究 eval() 并查看它在所有情况下的稳健性。谢谢!
    • 请注意,如果有人可以影响您记录的数据,这将是一个相当大的黑客攻击和严重的安全漏洞。您正在将所述数据作为 Python 代码执行。这完全不是一个强大的解决方案。了解正则表达式,它会得到回报!
    • 感谢您的建议!我确实知道正则表达式,但希望有某种模块可以智能地解释与对象格式匹配的字符串。再次感谢。
    【解决方案2】:

    只需在 [.所以你可以做 s.split('[')[-1].split(']')[0] 其中 s 是文件中的一行...

    【讨论】:

      【解决方案3】:

      您有一个嵌套语法,您正在尝试解析。尽管它的范围很窄,所以可以构造正则表达式 来处理它,但它会很脆弱。就像,真的脆弱。

      尝试使用ast。这有点复杂,所以我会尝试通过一个例子来解释(哈哈)。如果你想要 tl;dr,请跳到中间/结尾。

      我们正在列表节点中寻找一个名字,所以我们可以从那里开始。

      import ast
      
      s = "candidates(6,1,0,5,[ev(-1000,'C0009814','Stenosis','Acquired stenosis',[stenosis],[patf])])"
      
      mod = ast.parse(s)
      
      for node in ast.walk(mod):
          if isinstance(node, ast.List):
              print(node, list(ast.iter_child_nodes(node)))
      
      <_ast.List object at 0xb3f2ddec> [<_ast.Call object at 0xb3f2de0c>, <_ast.Load object at 0xb712756c>]
      <_ast.List object at 0xb3f2deec> [<_ast.Name object at 0xb3f2df0c>, <_ast.Load object at 0xb712756c>]
      <_ast.List object at 0xb3f2df2c> [<_ast.Name object at 0xb3f2df4c>, <_ast.Load object at 0xb712756c>]
      

      我们看到语法树中有三个ast.List 节点。第一个将是调用ev 的外部列表,而两个内部列表将包含那些裸露的ast.Name 节点。这就是我们想要达到的目标 - 你特别想要第二个。


      tl;博士在这里跳过

      我们可以让这一切变得更简单,我只是简单介绍一下我个人是如何探索这个语法树的。这是一个单一的衬里:

      s = "candidates(6,1,0,5,[ev(-1000,'C0009814','Stenosis','Acquired stenosis',[stenosis],[patf])])"
      
      mod = ast.parse(s)
      
      [next(ast.iter_fields(node)) for node in ast.walk(mod) if isinstance(node, ast.Name)]
      Out[62]: [('id', 'candidates'), ('id', 'ev'), ('id', 'stenosis'), ('id', 'patf')]
      

      所以只需抓住最后一个元素的第二个索引,这就是你的字符串。这种方法也适用于您的其他示例:

      s = "candidates(8,1,0,7,[ev(-875,'C0003501','Aortic Valve','Aortic valve structure',[aortic,valve],[bpoc])])"
      
      mod = ast.parse(s)
      
      [next(ast.iter_fields(node)) for node in ast.walk(mod) if isinstance(node, ast.Name)]
      Out[65]: 
      [('id', 'candidates'),
       ('id', 'ev'),
       ('id', 'aortic'),
       ('id', 'valve'),
       ('id', 'bpoc')]
      

      您可以使用这种方法从语法树中获取您想要的真正任何元素。只需使用ast.iter_fieldsast.iter_child_nodes 探索ast.walk 的输出即可。

      【讨论】:

      • 这看起来很有希望!我将开始将它应用到一些示例中,看看它的效果如何。谢谢!
      猜你喜欢
      • 2014-10-18
      • 2011-03-18
      • 2011-05-16
      • 2018-07-20
      • 2014-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-21
      相关资源
      最近更新 更多