拆分看起来像Python函数调用参数的字符串

时间:2015-07-21 18:34:24

标签: python

我正在尝试创建一个接受在python中看起来像函数调用的字符串的函数,并将参数返回给函数 例如:

"fun(1, bar(x+17, 1), arr = 's,y')"

将导致:

["1", "bar(x+17, 1)", "arr = 's,y'"]

使用正则表达式的问题是我不知道是否有可能不在括号或引号内的逗号分割。 感谢。

修改:此Python: splitting a function and arguments没有正确回答这些问题,因为它不会在括号或引号中处理逗号。

正如@Kevin所说,正则表达式无法解决此问题,因为它们无法处理嵌套的括号。

5 个答案:

答案 0 :(得分:3)

你可以通过

之类的东西简单地跟踪你自己的状态
def parse_arguments(s):
    openers = "{[\"'("
    closers = "}]\"')"
    state = []
    current = ""
    for c in s:
        if c == "," and not state:
           yield current
           current = ""
        else:
           current += c
           if c in openers:
              state.append(c)
           elif c in closers:
              assert state, "ERROR No Opener for %s"%c
              assert state[-1] == openers[closers.index(c)],"ERROR Mismatched %s %s"%(state[-1],c)
              state.pop(-1)
    assert not state, "ERROR Unexpected End, expected %s"%state[-1]
    yield current

print list(parse_arguments("1, bar(x+17, 1), arr = 's,y'"))

答案 1 :(得分:2)

试试这个复杂的分割函数。

>>> import re
>>> s = "fun(1, bar(x+17, 1), arr = 's,y')"
>>> [i.strip() for i in re.split(r'''^\w+\(|\)$|((?:\([^()]*\)|'[^']*'|"[^"]*"|[^'"(),])*)''', s) if i and i !=',']
['1', 'bar(x+17, 1)', "arr = 's,y'"]

答案 2 :(得分:1)

使用ast(抽象语法树)标准库模块进行操作会很不错,尽管它可能有点过分:

>>> import ast
>>> parsed = ast.parse("fun(1, bar(x+17, 1), arr='s, y')")
>>> ast.dump(p.body[0].value)
"Call(func=Name(id='fun', ctx=Load()), args=[Num(n=1), 
Call(func=Name(id='bar', ctx=Load()), args=[BinOp(left=Name(id='x', 
ctx=Load()), op=Add(), right=Num(n=17)), Num(n=1)], keywords=[], 
starargs=None, kwargs=None)], keywords=[keyword(arg='arr', 
value=Str(s='s, y'))], starargs=None, kwargs=None)"

不幸的是,没有标准的库方法可以将这些文件转回标准字符串,如"1""bar(x+17, 1)""arr='s, y'"。但是https://pypi.python.org/pypi/astor可能会这样做。

答案 3 :(得分:1)

re

您可以尝试使用['1', 'bar(x+17, 1)', "arr = 's,y'"]

输出:procrun

答案 4 :(得分:0)

基于Joran Beasley's answer,希望可以更好地处理字符串?唯一的变化是新的if臂,当我们在字符串中时,它允许任何字符,包括转义的引号。

def parse_arguments(s):
    openers = "{[\"'("
    closers = "}]\"')"
    state = []
    current = ""
    for c in s:
        if c == "," and not state:
            yield current
            current = ""
        else:
            current += c
            if state and state[-1] in "\"'":
                if c == state[-1] and current[-1] != "\\":
                    state.pop(-1)
            else:
                if c in openers:
                    state.append(c)
                elif c in closers:
                    assert state, "ERROR No Opener for %s" % c
                    assert (
                        state[-1] == openers[closers.index(c)]
                    ), "ERROR Mismatched %s %s" % (state[-1], c)
                    state.pop(-1)
    assert not state, "ERROR Unexpected End, expected %s" % state[-1]
    yield current