次のような文字列を解析したいと思います。
-o 1 --long "Some long string"
これに:
["-o", "1", "--long", 'Some long string']
または類似。
これは、(上記の出力のように)sys.argvで解析された入力でstartするgetoptまたはoptparseとは異なります。これを行うための標準的な方法はありますか?基本的に、これは引用符で囲まれた文字列を一緒に保ちながら「分割」します。
これまでの私の最高の機能:
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]
shlex モジュールが必要だと思います。
>>> import shlex
>>> shlex.split('-o 1 --long "Some long string"')
['-o', '1', '--long', 'Some long string']
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文字列で直接機能します。OnPython 3.x、itonlyは、bytes
オブジェクトではなく、[Unicode]文字列を受け入れます。
これは、シェルargv分割とまったく同じようには動作しません。また、CR、LF、およびTAB文字を\r
、\n
、および\t
として引用し、実際のCR、LF、TAB( shlex.split
はそれを行いません)。したがって、独自の関数を作成することは私のニーズに役立ちました。単純なシェルスタイルのargv分割が必要な場合は、shlex.split
の方が良いと思います。このコードは、実行のベースラインとして役立つ場合に備えて共有しています。少し違うもの。