Python中的递归嵌套表达式

问题描述:

我正在使用Python 2.6.4。Python中的递归嵌套表达式

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

给定select语句字段可能有几个嵌套圆括号,比如“ltrim(rtrim(to_char(base_field_name,format)))renamed_field_name ,“或只是”base_field_name“作为字段的简单情况,是否可以使用Python的re模块编写正则表达式来提取base_field_name?如果是这样,正则表达式会是什么样子?

>>> 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' 
+2

PS世界:亚历克斯·马尔泰利的告诉,你应该使用一个真正的解析器在这里。无论如何,如果你只想要一个快速的正则表达式,你可以使用它。但你应该真的使用一个解析器,因为这个正则表达式看起来相当难看:) – 2010-02-01 01:00:34

+0

我并没有追求一些看起来很漂亮的东西,因为它是一个让我获得我想要的数据的工具,所以我可以用它来做其他事情。 :)但是,谢谢,我的正则表达式是生锈的,我想有人可能会更好地知道。 – TheObserver 2010-02-01 01:15:09

正则表达式不适合解析“嵌套”结构。相反,尝试使用完整的解析工具包,例如pyparsing - 例如,专门用于解析SQL的pyparsing的示例可以找到herehere,例如(您无疑需要将示例作为起点,并且写一些你自己的解析代码,但是,它绝对不是太难)。

+1

+1记住的是,良好的括号表达式(当然,所有乔姆斯基型2种语言)需要比正则表达式更正确解析:) – Agos 2010-02-01 00:46:12

或者像Alex Martelli建议的表驱动解析器或手写递归下降解析器。他们不难,写作也很有意义。

这可能是不够好:

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

您需要做进一步的处理。例如,选取函数名称,并根据函数签名提取字段名称。

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

这为我打印'field_name,format',而不是'field_name',也不适用于简单字符串'field_name'。 – 2010-02-01 00:47:57

+0

你怎么知道每个函数都会接受相同的参数? – ziya 2010-02-01 01:20:11

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

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

's'包含原始字符串。

当然,这不是一般的解决办法,但...

+0

编译后的正则表达式应该比这更快。那么,我想我们并不着急,但仍然只是为了提高效率。 – 2010-02-01 01:30:15

+0

您可能会发现直接使用字符串更快。 很大程度上取决于正则表达式和您需要编写的等效代码的复杂性,以便在没有正则表达式的情况下执行此操作。 其实,你有没有试过比较它们? – 2010-02-01 01:59:16

+1

哦,如果我想要去等效的正则表达式,我会使用“\\(([^(),] +),”,它比纯粹的基于字符串的稍快。 他们都比你的正则表达式快一个数量级... – 2010-02-01 02:30:00

这里是一个非常哈克解析器,你想要做什么。

它通过调用要解析的文本'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)))')