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

4 投票
5 回答
4513 浏览
提问于 2025-04-16 05:10

问题

有一个程序文件,在某个地方包含了以下代码片段。

...

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)
    

问题

有没有办法用一个正则表达式来实现这个,而不是两个?

编辑

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

  1. Python正则表达式 - 如何从通配符表达式中捕获多个组?
  2. 哪些正则表达式类型支持捕获(与捕获组相对)?

5 个回答

2

为什么要用正则表达式(regex)?

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$']
2

Pyparsing 是一个很方便的工具,特别是在你不知道什么时候会遇到多余的空格、注释或者其他东西的时候。就像正则表达式中的命名组,这个例子定义了一个叫 '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']
3

针对你的问题“能不能用一个正则表达式来完成?”:可以,但在Python里不行。

如果你想要匹配并单独捕获不确定数量的匹配项,就像你举的例子那样,使用一个正则表达式的话,你需要一种支持捕获的正则引擎(而不是捕获组)。目前只有.NET和Perl 6支持这种功能。

所以在Python中,你要么需要分两步来做(先用find找到整个food(...)函数调用,然后再用第二个正则表达式通过findall找到单独的匹配项,就像Dingo建议的那样)。

或者你可以使用像Paul McGuire的pyparsing这样的解析器。

撰写回答