【问题标题】:Regex Python exclude some results正则表达式 Python 排除一些结果
【发布时间】:2017-05-08 15:50:43
【问题描述】:

有一个测试字符串:

Module([Assign([Name('a', Store())], Num(2)), Assign([Name('b', Store())], Num(3)), 赋值([Name('c', Store())], Str('Hello')), 赋值([Name('x', Store())], BinOp(Name('a', Load()), Add(), Name('b', 加载()))),分配([名称('x',存储())],名称('a',加载())), Expr(Call(Name('print', Load()), [Name('a', Load())], [], None, 无)), For(Name('i', Store()), Call(Name('range', Load()), [Num(10)], [], 无, 无), [Expr(Call(Name('print', Load()), [Name('a', 加载())],[],无,无))],[])])

我正在尝试从中获取所有已加载的变量名称。我的正则表达式是

[a-z]+(?=', Load)

结果如下: 如您所见,它还可以找到内置模块,例如 print、range。如何排除它们?要排除的值前面有

Call(Name(' 

我试过了

 (?=Call\(Name\(')[a-z]+(?=', Load)

但它没有成功。

我的代码是:

import re

test = '''Module([Assign([Name('a', Store())], Num(2)), Assign([Name('b', Store())], Num(3)), Assign([Name('c', Store())], Str('Hello')), Assign([Name('x', Store())], BinOp(Name('a', Load()), Add(), Name('b', Load()))), Assign([Name('x', Store())], Name('a', Load())), Expr(Call(Name('print', Load()), [Name('a', Load())], [], None, None)), For(Name('i', Store()), Call(Name('range', Load()), [Num(10)], [], None, None), [Expr(Call(Name('print', Load()), [Name('a', Load())], [], None, None))], [])])'''
print(re.findall(r"[a-z]+(?=', Load)", test))
print(re.findall(r"(?=Call\(Name\(')[a-z]+(?=', Load) ", test))

【问题讨论】:

  • 请出示您的完整代码。
  • 您不应该为此使用正则表达式。它已经处于最佳形式,能够步行找到您正在寻找的任何元素。虽然这里的答案可能会准确地从提供的特定示例中提取您寻求的数据,但没有任何正则表达式能够可靠地做到这一点。在下面检查我的答案。

标签: python regex abstract-syntax-tree parse-tree


【解决方案1】:

使用lookbehindword boundary

(?<!Call\(Name\(')\b\w+\b(?=', Load)

查看演示。

https://regex101.com/r/hdxlQ8/1

【讨论】:

    【解决方案2】:

    消极的回顾:

    (?<!Call\(Name\()'(\w+)(?=', Load)
    

    (?<!Call\()Name\('(\w+)', Load
    

    【讨论】:

      【解决方案3】:

      我为此使用了eval() 方法。我不推荐这种方式,但您可以使用它作为替代方法。

      这里test 是具有长字符串的变量。 filtered 变量有你想要的值列表。

      all = (re.findall(r"[a-z]+(?=', Load)", test))
      
      filtered = []
      for each in all:
          try:
              eval(each)
          except NameError:
              filtered.append(each)
          except:
              pass
      
      print filtered
      

      输出:

      ['a', 'b', 'a', 'a', 'a']
      

      我们尝试使用 eval() 方法执行每个字符串。如果没有任何具有该名称的变量、方法或类,python 解释器将抛出 NameError 异常,提示这不是方法或变量,因此我们将字符串附加/添加到过滤列表中。

      PS。像TypeError 这样的任何其他异常都会通过。

      【讨论】:

        【解决方案4】:

        这看起来像一棵解析树。由于无数原因,我不会使用正则表达式,其他人在一些漂亮的famous posts 中更好地解释了这一点(当然,该帖子使用 [x]html 但教训仍然存在,不要使用正则表达式来解析更复杂的语法)。

        我的理解是 AST 和在这种情况下实际的具体解析树使用上下文无关语法,因此不是正则的,不能使用正则表达式可靠地解析。另外,就步行能力而言,该代码已经处于非常方便的状态。如果有任何东西重新创建对象并遍历树,同时知道变量名称将是 Assign 语句的左侧终端的规则,其值在右侧。与使用正则表达式相比,这肯定会花费更少的时间并减少头痛。

        帮自己一个忙,不要尝试使用正则表达式,除非您处理的是已知的少量此类。

        对于further reading

        【讨论】:

        • 非常感谢。是的,它确实是一个 AST。我正在尝试使用内置的 Python AST 模块来查找哪些变量已初始化(例如 a = 4)但未在代码中使用。我的想法是从 AST 转储中获取此信息,因为使用的变量在此处标记为已加载..
        • @trthhrtz 我没有使用过 AST 模块,但我想它必须提供一种遍历树的方法,这可能是你想要的
        • @trthhrtz 也是,这听起来像是一个好的 linter 可以处理的事情。必须有某种 python 包可以做到这一点,无论您是想要功能还是只是想看看其他人是如何解决这个问题的
        猜你喜欢
        • 2022-12-09
        • 2022-12-11
        • 1970-01-01
        • 2021-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多