您可以使用单个正则表达式来解析函数参数吗?

时间:2010-10-07 20:33:29

标签: python regex parsing

问题

程序文件在文件中的某个位置包含以下代码段。

...

food($apples$ , $oranges$ , $pears$ , $tomato$){
  ...
}

...

此函数可能包含任意数量的参数,但它们必须是以逗号分隔的字符串。所有参数字符串都是小写字。

我希望能够使用正则表达式解析每个参数。例如,python中的结果列表如下:

["apples", "oranges", "pears", "tomato"]

尝试解决方案

使用python RE模块,我可以通过将问题分成两部分来实现这一目标。

  1. 在代码中找到函数并提取参数列表。

    plist = re.search(r'food\((.*)\)', programString).group(1)
    
  2. 使用其他正则表达式拆分列表。

    params = re.findall(r'[a-z]+', plist)
    
  3. 问题

    无论如何,我可以用一个正则表达而不是两个来实现这个目的吗?

    修改

    感谢Tim Pietzcker的回答,我找到了一些相关的问题:

    1. Python regular expressions - how to capture multiple groups from a wildcard expression?
    2. Which regex flavors support captures (as opposed to capturing groups)?

5 个答案:

答案 0 :(得分:2)

当您不知道什么时候会遇到额外的空白,评论等等时,Pyparsing对于这种事情很方便。与RE中的命名组一样,此示例定义结果名称'parameters',用于检索所需数据:

>>> code = """\
... ...
...
... food($apples$ , $oranges$ , $pears$ , $tomato$){
...   ...
... }
... ...
... food($peanuts$, $popcorn$ ,$candybars$ ,$icecream$){
...   ...
... }
... """
>>> from pyparsing import *
>>> LPAR,RPAR,LBRACE,RBRACE,DOLLAR = map(Suppress,"(){}$")
>>> param = DOLLAR + Word(alphas) + DOLLAR
>>> funcCall = "food" + LPAR + delimitedList(param)("parameters") + RPAR + LBRACE
>>> for fn in funcCall.searchString(code):
...   print fn.parameters
...
['apples', 'oranges', 'pears', 'tomato']
['peanuts', 'popcorn', 'candybars', 'icecream']

如果我将第二个功能更改为:

... food($peanuts$, $popcorn$ ,/*$candybars$ ,*/$icecream$){

然后添加以下行:

>>> funcCall.ignore(cStyleComment)

然后我得到:

>>> for fn in funcCall.searchString(code):
...   print fn.parameters
...
['apples', 'oranges', 'pears', 'tomato']
['peanuts', 'popcorn', 'icecream']

答案 1 :(得分:2)

回答你的问题“它可以在一个正则表达式中完成吗?”:是的,但不是用Python。

如果你想匹配和捕获(单独)一个未知数量的匹配,就像在你的例子中一样,只使用一个正则表达式,那么你需要a regex engine that supports captures (as opposed to capturing groups)。目前只有.NET和Perl 6才能这样做。

所以在Python中,你需要分两步完成(find整个food(...)函数调用,然后findall个人匹配第二个正则表达式,如Dingo所建议的那样)

或者像Paul McGuire的pyparsing一样使用解析器。

答案 2 :(得分:1)

为何选择正则表达式?

for line in open("file"):
    line=line.rstrip()
    if line.lstrip().startswith("food") :
        for item in line.split(")"):
            if "food" in item:
                print item.split("(")[-1].split(",")

输出

$ ./python.py
['$apples$ ', ' $oranges$ ', ' $pears$ ', ' $tomato$']

答案 3 :(得分:0)

params = re.findall(r'\$([a-z]+)\$', programString)

答案 4 :(得分:0)

像这样的正则表达式应该有效

food\((\$(?<parm>\w+)\$\s*,?\s*)+\).*

它将所有匹配的参数名称放在'parm'组