Прежде чем я узнал о 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
объекты.
Это не ведет себя точно так же, как разбиение оболочки argv - оно также позволяет заключать в кавычки символы CR, LF и TAB как \r
, \n
и \t
, преобразовывая их в реальные CR, LF, TAB shlex.split
этого не делает). Поэтому написание моей собственной функции было полезно для моих нужд. Я думаю, shlex.split
лучше, если вы просто хотите расщепление argv в стиле shell. Я делюсь этим кодом на тот случай, если он полезен в качестве основы для выполнения чего-то немного другого.