如何解析类似sys.argv的字符串
我想要解析一个像这样的字符串:
-o 1 --long "Some long string"
变成这样:
["-o", "1", "--long", 'Some long string']
或者类似的格式。
这和getopt或optparse不一样,因为它们是从sys.argv解析输入开始的(就像我上面展示的输出)。有没有什么标准的方法可以做到这一点呢?基本上,这就是在“拆分”字符串的同时保持引号中的内容不被分开。
到目前为止,我写的最好的函数是:
import csv
def split_quote(string,quotechar='"'):
'''
>>> split_quote('--blah "Some argument" here')
['--blah', 'Some argument', 'here']
>>> split_quote("--blah 'Some argument' here", quotechar="'")
['--blah', 'Some argument', 'here']
'''
s = csv.StringIO(string)
C = csv.reader(s, delimiter=" ",quotechar=quotechar)
return list(C)[0]
2 个回答
3
在我知道有了 shlex.split
之前,我自己写了以下代码:
import sys
_WORD_DIVIDERS = set((' ', '\t', '\r', '\n'))
_QUOTE_CHARS_DICT = {
'\\': '\\',
' ': ' ',
'"': '"',
'r': '\r',
'n': '\n',
't': '\t',
}
def _raise_type_error():
raise TypeError("Bytes must be decoded to Unicode first")
def parse_to_argv_gen(instring):
is_in_quotes = False
instring_iter = iter(instring)
join_string = instring[0:0]
c_list = []
c = ' '
while True:
# Skip whitespace
try:
while True:
if not isinstance(c, str) and sys.version_info[0] >= 3:
_raise_type_error()
if c not in _WORD_DIVIDERS:
break
c = next(instring_iter)
except StopIteration:
break
# Read word
try:
while True:
if not isinstance(c, str) and sys.version_info[0] >= 3:
_raise_type_error()
if not is_in_quotes and c in _WORD_DIVIDERS:
break
if c == '"':
is_in_quotes = not is_in_quotes
c = None
elif c == '\\':
c = next(instring_iter)
c = _QUOTE_CHARS_DICT.get(c)
if c is not None:
c_list.append(c)
c = next(instring_iter)
yield join_string.join(c_list)
c_list = []
except StopIteration:
yield join_string.join(c_list)
break
def parse_to_argv(instring):
return list(parse_to_argv_gen(instring))
这段代码在 Python 2.x 和 3.x 都能用。在 Python 2.x 中,它可以直接处理字节字符串和 Unicode 字符串。而在 Python 3.x 中,它 只 接受 [Unicode] 字符串,不接受 bytes
对象。
这段代码的行为和 shell 中的参数分割不完全一样——它还允许将回车(CR)、换行(LF)和制表符(TAB)字符用 \r
、\n
和 \t
来表示,并将它们转换成真正的回车、换行和制表符(而 shlex.split
并不会这样做)。所以我自己写这个函数是为了满足我的需求。我想如果你只是想要简单的 shell 风格的参数分割,使用 shlex.split
会更好。我分享这段代码是希望它能作为一个基础,帮助你做一些稍微不同的事情。
97
我觉得你想要的是 shlex 这个模块。
>>> import shlex
>>> shlex.split('-o 1 --long "Some long string"')
['-o', '1', '--long', 'Some long string']