代码之家  ›  专栏  ›  技术社区  ›  sligocki

在python中提取嵌套正则表达式的所有匹配项

  •  1
  • sligocki  · 技术社区  · 15 年前

    我正试图解析满足python regex的项目列表

    r'\A(("[\w\s]+"|\w+)\s+)*\Z'
    

    也就是说,它是一个空格分隔的列表,除了在带引号的字符串中允许使用空格。我想得到列表中的项目列表(即与

    r'("[\w\s]+"|\w+)'
    

    部分。因此,例如

    >>> parse('foo "bar baz" "bob" ')
    ['foo', '"bar baz"', '"bob"']
    

    用python re做这个有什么好方法吗?

    很多事情都不太管用。例如

    >>> re.match(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
    '"bob"'
    

    只返回它匹配的最后一个。另一方面

    >>> re.findall(r'("[\w\s]+"|\w+)', 'foo "bar baz" "bob" ')
    ['foo', '"bar baz"', '"bob"']
    

    但它也接受像

    >>> re.findall(r'("[\w\s]+"|\w+)', 'foo "bar b-&&az" "bob" ')
    ['foo', 'bar', 'b', 'az', '" "', 'bob']
    

    那么有没有什么方法可以使用原始的regex并获取与组2匹配的所有项呢?有点像

    >>> re.match_multigroup(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
    ['foo', '"bar baz"', '"bob"']
    >>> re.match_multigroup(r'("[\w\s]+"|\w+)', 'foo "bar b-&&az" "bob" ')
    None
    

    编辑:IT 重要的是,我保留输出中的引号,因此我不希望

    >>> re.match_multigroup(r'\A(("[\w\s]+"|\w+)\s+)*\Z', 'foo "bar baz" "bob" ').group(2)
    ['foo', 'bar baz', 'bob']
    

    因为那时我不知道鲍勃是否被引用。

    3 回复  |  直到 15 年前
        1
  •  2
  •   SilentGhost    15 年前

    我不认为regex是正确的工具。尝试 csv 模块:

    >>> s = 'foo "bar baz" "bob" '
    >>> for i in csv.reader([s], delimiter=' '):
        print(i)
    
    
    ['foo', 'bar baz', 'bob', '']
    
        2
  •  1
  •   Alan Moore Chris Ballance    15 年前

    这里有一个解决方案,可以在任何不在一对引号内的空白处进行拆分:

    re.split('\s+(?=[^"]*(?:"[^"]*"[^"]*)*$)', target)
    

    只有在刚刚匹配的空白前面有偶数个引号时,lookahead才会成功。如果文本中带引号的部分可以包含转义引号,则可能需要更复杂的regex,具体取决于转义的方式。

        3
  •  1
  •   sligocki    15 年前

    好吧,我决定分两步来做。

    首先,我检查表达式在语法上是否有效,然后将其分解为各个部分:

    def parse(expr):
        if re.match(r'\A(("[\w\s]+"|\w+)\s+)*\Z', expr):
            return re.findall(r'("[\w\s]+"|\w+)', expr)
    

    所以:

    >>> parse('foo "bar baz" "bob" ')
    ['foo', '"bar baz"', '"bob"']
    >>> parse('foo "bar b-&&az" "bob" ')
    >>> parse('foo "bar" ')
    ['foo', '"bar"']
    >>> parse('"foo" bar ')
    ['"foo"', 'bar']
    >>> parse('foo"bar baz" "bob" ')
    >>> parse('&&')
    

    我大约90%确信这个方法适用于所有字符串,但是如果有人有更通用的解决方案,我仍然会感兴趣,在我看来这有点笨拙。

    感谢SilentGhost和Alan Moore的帮助。我以前不知道python csv或regex lookaheads,了解这些可能对我有帮助。