我想要一种简洁的方法来解析以强制列表元素(未指定的数字)开头的单行字符串,并使用=
以字典式定义结束。
,
而空格应该成为元素的一部分 - 排除shlex
。 ,
,则用户需要引用"
"key=value,with,comma"
key="value,with,comma"
- 任何更容易实施的内容让我们调用函数opts
并让它返回list
和dict
,
以下是一些输入示例和所需结果:
opts('dog,cat') # -> ["dog", "cat"], {}
opts('big fish,cat') # -> ["big fish", "cat"], {}
opts('"a dog, a cat",a fish') # -> ["a dog, a cat", "a fish"], {}
opts('key=value') # -> [] {'key':'value'}
opts('key=the value,x=y') # -> [] {'key':'the value', 'x':'y'}
opts('dog, big fish, eats="any, but peas", flies = no! '
# -> ['dog','big fish'], {'eats':'any, but peas', 'flies':'no!' }
我忽略了shlex
,argparse
,optparse
和configparser
,我无法看到我应该如何处理这些问题。不过,我不确定正则表达式是否会破解这个问题。我认为json
对语法有点过于严格。和eval
一样,如果我更喜欢(因为它解析python; - ))
我在macro
中的手动解决方案不是很灵活,我希望将其参数处理替换为上述更一般的opts(s)
函数:
def macro(s):
kw = { 'see':u"\\see", 'type':u"Chapter", 'title': u'??' }
params = s.split(",")
kw['label'] = params[0]
if len(params) > 1: # very inflexible
kw['title'] = params[1]
for param in params[2:]: # wrong if p[1] is already key=value
key, value = param.split("=",1) # doesn't handle anything, too simple
kw[key] = value
# ...rest of code...
目标是在这里使用可重用的函数opts
:
def macro_see(s):
ls, kw = opts(s)
# ...rest of code...
答案 0 :(得分:1)
您可能想要的是创建自己的分割功能,并在“引入”时切换标记。这样的事情:
def my_split(string, deli):
res = []
flag = True
start = 0
for i, c in enumerate(string):
if c == '"':
if flag:
flag = False
else:
flag = True
if c == deli and flag:
res.append(string[start:i])
start = i+1
res.append(string[start:])
return res
从那里开始,这很容易:
def opts(s):
items = map(lambda x: x.strip(), my_split(s, ','))
# collect
ls = []
kw = {}
for item in items:
if '=' in item:
k, v = item.split('=', 1)
kw[k.strip()] = v.strip()
else:
ls.append(item)
return ls, kw
这并不完美,你可能还需要做一些事情,但这绝对是一个开始。
答案 1 :(得分:1)
这是一种方法,我按下输入,使其符合python函数参数的语法要求,然后通过eval利用python解释器来解析它们。
import re
s = 'hog, "cog" , dog, bog, "big fish", eats="any, but peas", flies = "no!" '
# I think this will add quotes around any unquoted positional arguments
s = re.sub('(^|,)\ *([^\"\',\ ]+)\ *(?=,|$)', r'\1"\2"', s)
def f(*args, **kwargs):
return (args, kwargs)
print eval("f("+s+")", {'f':f})
输出:
(('hog', 'cog', 'dog', 'bog', 'big fish'), {'flies': 'no!', 'eats': 'any, but peas'})
答案 2 :(得分:1)
在此解决方案中,opts
基本上与yuvi相同(添加了strip
)。分割器是shlex
的自定义,使用posix
模式处理引号。
def mylex(x):
lex = shlex.shlex(x, posix=True)
lex.whitespace = ','
lex.whitespace_split = True
return list(lex)
def opts(x):
ll = []
dd = {}
items = mylex(x)
for item in items:
if '=' in item:
k, v = item.split('=',1)
dd[k.strip(' "')] = v.strip(' "')
else:
ll.append(item.strip(' "'))
return (ll,dd)
通过:
trials = [
['dog,cat',(["dog", "cat"], {})],
['big fish,cat',(["big fish", "cat"], {})],
['"a dog, a cat",a fish',(["a dog, a cat", "a fish"], {})],
['key=value',([], {'key':'value'})],
['key=the value,x=y',([], {'key':'the value', 'x':'y'})],
['dog, big fish, eats="any, but peas", flies = no!',(['dog','big fish'], {'eats':'any, but peas', 'flies':'no!' })],
]
for (x,y) in trials:
print('%r'%x)
args = opts(x)
print(args)
if args != y:
print('error, %r'%y)
print('')