【问题标题】:recursive nested expression in PythonPython中的递归嵌套表达式
【发布时间】:2010-02-01 00:27:04
【问题描述】:

我正在使用 Python 2.6.4。

我在一个文本文件中有一系列选择语句,我需要从每个选择查询中提取字段名称。如果某些字段不使用 to_char() 等嵌套函数,这将很容易。

给定可能具有多个嵌套括号的选择语句字段,例如“ltrim(rtrim(to_char(base_field_name, format))) 重命名字段名称”或仅将“base_field_name”作为字段的简单情况,是否可以使用 Python 的 re编写正则表达式以提取 base_field_name 的模块?如果是这样,正则表达式会是什么样子?

【问题讨论】:

    标签: python regex nested expression


    【解决方案1】:

    正则表达式不适合解析“嵌套”结构。相反,请尝试使用成熟的解析工具包,例如 pyparsing - 例如,可以在 herehere 中找到使用 pyparsing 来解析 SQL 的示例(毫无疑问,您只需举几个例子)作为起点,自己写一些解析代码,但是,绝对不会太难)。

    【讨论】:

    • +1 用于记住带括号的表达式(好吧,所有 Chomsky Type-2 语言)需要的不仅仅是正则表达式才能正确解析 :)
    • 你不正确,它们适合那个(只是python还不支持它)......纯PCRE正则表达式匹配嵌套成对括号看起来像^(?P<pn>\((?P<v>((?>[^()]+)|(?P>pn))*)\))$,它会匹配@ 987654325@ 和匹配组 v 将包含 (1+2)*3
    【解决方案2】:
    >>> import re
    >>> string = 'ltrim(rtrim(to_char(base_field_name, format))) renamed_field_name'
    >>> rx = re.compile('^(.*?\()*(.+?)(,.*?)*(,|\).*?)*$')
    >>> rx.search(string).group(2)
    'base_field_name'
    >>> rx.search('base_field_name').group(2)
    'base_field_name'
    

    【讨论】:

    • PS:正如 Alex Martelli 所说,您应该在这里使用真正的解析器。无论如何,如果您只想要一个可以正常工作的快速正则表达式,您可以使用它。但是你真的应该使用解析器,因为这个正则表达式看起来很丑:)
    • 我不追求看起来很漂亮的东西,因为它可以让我得到我想要的数据,这样我就可以用它做其他事情了。 :) 但是谢谢,我的正则表达式生锈了,我想有人可能知道得更好。
    【解决方案3】:

    要么是 Alex Martelli 建议的表驱动解析器,要么是手写的递归下降解析器。写起来并不难,而且很有收获。

    【讨论】:

      【解决方案4】:

      这可能已经足够了:

      import re
      print re.match(r".*\(([^\)]+)\)", "ltrim(to_char(field_name, format)))").group(1)
      

      您需要进行进一步处理。比如把函数名也取出来,根据函数签名拉取字段名。

      .*(\w+)\(([^\)]+)\)
      

      【讨论】:

      • 这对我来说打印的是 'field_name, format',而不是 'field_name',也不适用于简单的字符串 'field_name'。
      • 你怎么知道每个函数都会接受相同的参数?
      【解决方案5】:

      这是一个非常 hacky 的解析器,可以满足您的需求。

      它的工作原理是在要解析的文本上调用“eval”,将所有标识符映射到一个返回其第一个参数的函数(我猜这就是你想要的例子)。

      class FakeFunction(object):
          def __init__(self, name):
              self.name = name
          def __call__(self, *args):
              return args[0]
          def __str__(self):
              return self.name
      
      class FakeGlobals(dict):
          def __getitem__(self, x):
              return FakeFunction(x)
      
      def ExtractBaseFieldName(x):
          return eval(x, FakeGlobals())
      
      print ExtractBaseFieldName('ltrim(rtrim(to_char(base_field_name, format)))')
      

      【讨论】:

        【解决方案6】:

        你真的需要正则表达式吗?为了得到你在那里的那个,我会使用

          s[s.rfind('(')+1:s.find(')')].split(',')[0]
        

        's' 包含原始字符串。

        当然,这不是一个通用的解决方案,但是……

        【讨论】:

        • 编译的正则表达式应该比这快得多。好吧,我想我们并不着急,但仍然只是为了提高效率。
        • 您可能会发现直接使用字符串会更快。很大程度上取决于正则表达式和您需要编写的等效代码的复杂性来完成没有正则表达式的事情。实际上,您是否尝试过比较它们?
        • 哦,如果我想使用等效的正则表达式,我会使用“\(([^(),]+)”,这比纯粹的基于字符串的。它们都比你的正则表达式快一个数量级......
        猜你喜欢
        • 1970-01-01
        • 2017-07-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-19
        • 2014-03-06
        • 2021-01-12
        • 2018-06-24
        相关资源
        最近更新 更多