代码之家  ›  专栏  ›  技术社区  ›  Gregg Lind

python,如何解析字符串使其看起来像sys.argv

  •  35
  • Gregg Lind  · 技术社区  · 17 年前

    我想分析这样的字符串:

    -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 回复  |  直到 13 年前
        1
  •  73
  •   Jacob Gabrielson    17 年前

    我相信你想要 shlex 模块。

    >>> import shlex
    >>> shlex.split('-o 1 --long "Some long string"')
    ['-o', '1', '--long', 'Some long string']
    
        2
  •  2
  •   Craig McQueen Dr. Watson    13 年前

    在我意识到之前 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 argv splitting_的行为不完全相同,它还允许引用cr、lf和tab字符作为 \r , \n \t ,将它们转换为真正的CR、LF、TAB( 施莱克分裂 不这样做)。所以写我自己的函数对我的需要是有用的。我猜 施莱克分裂 如果只需要简单的外壳式argv拆分,则更好。我正在分享这段代码,以防它作为做一些稍微不同的事情的基线有用。