如何将任意选项字符串解析为python字典

时间:2012-08-17 17:09:30

标签: python string dictionary

我正在尝试找到最恐怖的方式来获取包含命令行选项的字符串:

"-t 500 -x -c 3 -d"

将其变成字典

{"-t":"500", "-x":True, "-c":"3", "-d": True}

更新:该字符串还应该能够包含--long选项,以及中间带有破折号的字词:

"-t 500 -x -c 3 -d --long-option 456 -testing weird-behaviour"

在建议我查看OptionParse模块之前,请记住我不知道有效选项是什么或类似的东西,我只是想把字符串放到字典中以允许根据不同的字典修改它选项。

我正在考虑的方法是使用split()将项目放入列表中,然后遍历列表并查找以短划线“ - ”开头的项目并将其用作键,然后以某种方式进入值列表中的下一个项目。我遇到的问题是没有值的选项。我想做类似的事情:

for i in range(0, len(opt_list)):
        if opt_list[i][0] == "-":
            if len(opt_list) > i+1 and not opt_list[i+1][0] == "-":
                opt_dict[opt_list[i]] = opt_list[i+1] 
            else:
                opt_dict[opt_list[i]] = True

但是,当我这样做时,我似乎用C编程而不是Python ...

7 个答案:

答案 0 :(得分:6)

要正确处理引号内的空格,可以使用shlex.split()

import shlex

cmdln_args = ('-t 500 -x -c 3 -d --long-option 456 '
              '-testing "weird -behaviour" -m "--inside"')

args = shlex.split(cmdln_args)
options = {k: True if v.startswith('-') else v
           for k,v in zip(args, args[1:]+["--"]) if k.startswith('-')}

from pprint import pprint
pprint(options)

输出

{'--inside': True,
 '--long-option': '456',
 '-c': '3',
 '-d': True,
 '-m': True,
 '-t': '500',
 '-testing': 'weird -behaviour',
 '-x': True}

答案 1 :(得分:3)

你可以像这样使用正则表达式:

import re

args = "-t 500 -x -c 3 -d --long-option 456 -testing weird-behaviour"
matches = re.findall(r'(--?[\w-]+)(.*?)(?= -|$)', args)

result = {}
for match in matches:
    result[match[0]] = True if not match[1] else match[1].strip()

print result

,结果等于

{
'-d': True, 
'-c': '3', 
'-t': '500', 
'--long-option': '456', 
'-x': True, 
'-testing': 'weird-behaviour'
}

正则表达式细分:

(--?[\w-]+)(.*?)(?= -|$)

  • (--?[\w-]+)匹配以“ - ”或“ - ”开头的任何字符或单词(单词中允许的短划线)。
  • (.*?)使用问号在non-greedy or minimal fashion中对任意字符进行0次或多次匹配。
  • (?= -|$)是一个积极的向前看。它会检查我们要查找的内容后跟一个“ - ”或字符串的结尾,但它不会在匹配中包含它。

请注意在此正则表达式中使用括号。这些用于创建组,因此当我们调用findall时,它会将它们分成元组。

答案 2 :(得分:2)

人类的争论解析 - https://github.com/kennethreitz/args

答案 3 :(得分:1)

我不能用最Pythonic的方式说话,但这里有一个单行:

opt_list = "-t 500 -x -c 3 -d"

dict((e if len(e) >1 else (e[0],True) for e in (elem.split() 
      for elem in ('-'+d for d in opt_list.split('-') if d))))

>>>{'-t': '500', '-x': True, '-c': '3', '-d': True}

[编辑:正如马蒂亚斯指出的那样,这对于其中带有“ - ”的值不起作用]

...但是,一般来说,当你在选项值中允许' - '时,我认为OP的答案不能毫无疑问地解决。

考虑以下简单选项:

“ - a -b”

这是:

  • {' - '':' - b'},
  • {'a - ':True,' - b':True}

???

答案 4 :(得分:0)

>>> results = "-t 500 -x -c 3 -d".split()
>>> rd = {}
>>> while i < len(results):
...    if results[i].startswith("-"):
...       rd[results[i]]=True
...       try:
...          if not results[i+1].startswith("-"):
...             rd[results[i]] = results[i+1]
...       except IndexError: pass
...    i+=1
...
>>> rd
{'-t': '500', '-x': True, '-c': '3', '-d': True}

但与你的相似......

答案 5 :(得分:0)

它最初出现的一个更难的问题,这是我的第一次尝试。它只是遍历参数并检查它们是否以-开头。如果是这样,并且下一个参数没有,则将这两个项添加到一个词典中,否则添加当前参数和True。如果参数列表中的最后一项以try开头,则需要-

args = "-t 500 -x -c 3 -d".split()

d = {}

for i, item in enumerate(args):
    if item.startswith('-'):
        try:
            if args[i+1].startswith('-'):
                d[item] = True
            else:
                d[item] = args[i+1]
        except IndexError:
                d[item] = True

print d # prints {'-t': '500', '-x': True, '-c': '3', '-d': True}

修改:受Gerrat's splitting on -启发的替代解决方案如下:

args = "-t 500 -x -c 3 -d".split('-')

d = {}

for arg in args:
    if arg:
        try:
            k, v = arg.split()
        except ValueError:
            k, v = arg.strip(), True

        d[k] = v

但是,正如马蒂亚斯指出的那样,如果选项和值中包含-,这可能无效。

答案 6 :(得分:0)

import re

myDictionnary = {}

strPattern1 = "-[0-9a-z ]*"
strPattern2 = "-([0-9a-z]+) *(.*)"
strToParse = "-t 500 -x -c 3 -d"

listKeyValues = re.findall(strPattern1, strToParse)

for kv in listKeyValues:

    match = re.search(strPattern2, kv)

    key = match.group(1)
    value = match.group(2)

    if len(value) > 0:
        myDictionnary[key] = value
    else:
        myDictionnary[key] = True