9

我试图找到最 Pythonic 的方式来获取包含命令行选项的字符串:

"-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 编程......

4

7 回答 7

8

要正确处理引号内的空格,您可以使用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}
于 2012-08-17T21:58:15.407 回答
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-]+)匹配以“-”或“--”开头的任何字符或单词(单词中允许使用破折号)。
  • (.*?)使用问号以非贪婪或最小方式匹配任何字符 0 次或更多次。
  • (?= -|$)是一个积极的前瞻。它会检查我们正在寻找的内容是否跟在“-”或字符串的结尾,但它不会将其包含在匹配项中。

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

于 2012-08-17T18:39:15.013 回答
2

人类的参数解析 - https://github.com/kennethreitz/args

于 2012-08-17T21:27:11.817 回答
1

我不能说最多的Pythonic方式,但这里有一个 1-liner:

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”

这是:

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

???

于 2012-08-17T17:29:47.877 回答
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}

但与你所拥有的非常相似..

于 2012-08-17T17:38:32.623 回答
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 分裂-启发的另一种解决方案如下:

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

-但是,正如 Matthias 指出的那样,如果选项和值中包含s ,这可能不起作用。

于 2012-08-17T17:44:06.297 回答
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
于 2012-08-17T18:58:51.420 回答