匹配和解析以从复杂的字符串中提取信息

时间:2014-01-15 15:14:46

标签: python regex string

我有一个字符串,其中包含来自'arg0, arg1=1, arg2=None'等函数的参数,并希望提取每个参数的名称和默认值。我处理简单的案件没有问题。问题是字符串,列表和元组作为默认参数。这是我目前的尝试

def get_args(s):
    regex = r'([a-zA-Z0-9._]*)\s*=?\s*(.*)'
    # save and replace quoted strings
    str_quoted = re.findall(r'([\"\'].*?[\"\'])', s)
    for quote in str_quoted:
        s = s.replace(quote, '%s')
    # split arguments
    args = re.split("[ ]{0,10},[ ]{0,10}", s)
    # restore quoted strings
    args = ('\n'.join(args) % tuple(str_quoted)).split('\n')
    # return arguments
    return [{
        'name': re.match(regex, arg).group(1),
        'def': re.match(regex, arg).group(2)
    } for arg in args]

一些示例字符串

s1 = 'arg0, arg1=1, arg2=None'
s2 = 'arg0, arg1=",", arg2=None'
s3 = 'arg0, arg1=[1, 2], arg2=[1, 2]'
s4 = 'arg0, arg1=(1, 2), arg2=(1, 2)'
s5 = 'arg0, arg1=[1, [1,2,3]], arg2=[1, 2]'

get_args(s1)使用此输出(带有参数名称和默认值的字典列表)

[{'def': '', 'name': 'arg0'},
 {'def': '1', 'name': 'arg1'},
 {'def': 'None', 'name': 'arg2'}]

s2也适用,但其他人则不行。我目前的字符串解决方案是临时替换它们(参见str_quoted部分)。我为列表或元组尝试了类似的东西,但很快遇到了问题。

get_args函数的任何建议,可以可靠地将参数与默认值分开?

2 个答案:

答案 0 :(得分:1)

在字符串的两边附加花括号并执行json.loads然后你只需处理一个字典。忘记了。

arg_str = yourstring
arg_str = '{%s}' % arg_str
import json
dict_arg = json.loads(arg_str)

如果你得到错误,可能是因为json只接受双引号,如果你的参数有单引号,则替换它们然后加载

答案 1 :(得分:0)

这是我想出的。 Martijn Pieters和其他一些海报是正确的,正确的解析器将是正确的方法。我选择了一个简单的迭代遍历字符,它处理上面的所有例子,更多,以及无限的嵌套。也许不那么优雅,但它的工作做得很好。但是仍然没有解决一些特殊情况(例如转义字符)

def get_args(s):
    # prepare
    syn = {'"': False, "'": False, '(': 0, '[': 0}
    mapping = {')': '(', ']': '['}
    args = []
    arg = {'name': '', 'def': ''}
    type = 'name'
    # iterate through chars
    for c in s:
        bracket = syn['('] == 0 and syn['['] == 0
        quote = (syn['"'] is True and c is not '"') or (syn["'"] is True and c is not "'")
        # add to argument definition
        if re.match(r"[a-zA-Z0-9._ ]", c) or quote:
            arg[type] += c
        # quotes
        elif re.match(r"[\"\']", c):
            syn[c] = not syn[c]
            arg[type] += c
        # brackets
        elif re.match(r"[\(\[]", c):
            syn[c] += 1
            arg[type] += c
        elif re.match(r"[\)\]]", c):
            syn[mapping[c]] -= 1
            arg[type] += c
        # '=' to define default value
        elif re.match(r"=", c) and bracket:
            type = 'def'
        # ',' to seperate arguments
        elif re.match(r",", c) and bracket:
            type = 'name'
            args.append({'name': arg['name'].strip(), 'def': arg['def'].strip()})
            arg = {'name': '', 'def': ''}
        else:
            arg[type] += c
    # add last arg
    if syn['('] == 0 and syn['['] == 0 and syn['"'] is False and syn["'"] is False:
        args.append({'name': arg['name'].strip(), 'def': arg['def'].strip()})
    # return
    return args