我有一个字符串,其中包含来自'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
函数的任何建议,可以可靠地将参数与默认值分开?
答案 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