正则表达贪心问题

时间:2013-03-11 16:06:35

标签: python regex

我需要使用Python解析一个字符串并提取由:(冒号)分隔的2个标记,这些标记可以用单引号,双引号或无引号括起来。

工作案例:

# <input string> -> <tuple that should return> 

1) abc:def -> (abc, def)
2) abc:"def" -> (abc, def)
3) "abc":def -> (abc, def)
4) "abc":"def" -> (abc, def)
5) "a:bc":abc -> (a:bc, abc)

示例案例不起作用:

# <input string> -> <tuple that should return> 

6) abc:"a:bc" -> (abc, a:bc)
7) "abcdef" -> (abcdef,)

使用的正则表达式是:

>>> import re
>>> rex = re.compile(r"(?P<fquote>[\'\"]?)"
                     r"(?P<user>.+)"
                     r"(?P=fquote)"
                     r"(?:\:"
                     r"(?P<squote>[\'\"]?)"
                     r"(?P<pass>.+)"
                     r"(?P=squote))")

我有2个问题,首先是样本案例6)和7)不起作用,第二个问题rex.match后我希望所有组都匹配但不是fquotesquote个。我的意思是现在rex.match("'abc':'def').groups()返回("'", "abc", "'", "def"),我只想要("abc", "def")

有什么想法吗?

由于

3 个答案:

答案 0 :(得分:1)

您可以在此使用csv模块而不是正则表达式:

inputs = [
    'abc:def', 'abc:"def"', '"abc":def', '"abc":"def"', '"a:bc":abc', #working
    'abc:"a:bc"', 'abcdef' # not working

]

import csv
for idx, el in enumerate(inputs, start=1):
    print idx, tuple(next(csv.reader([el], delimiter=':')))

这给了你:

1 ('abc', 'def')
2 ('abc', 'def')
3 ('abc', 'def')
4 ('abc', 'def')
5 ('a:bc', 'abc')
6 ('abc', 'a:bc')
7 ('abcdef',)

答案 1 :(得分:1)

def foo(string):
    rex = re.compile(r"(?P<fquote>[\'\"]?)"
                     r"(?P<user>.+?)"
                     r"(?:(?P=fquote))"
                     r"(?:\:"
                     r"(?P<squote>[\'\"]?)"
                     r"(?P<pass>.+)"
                     r"(?P=squote))"
                     r"|(?P<sfquote>[\'\"]?)"
                     r"(?P<suser>.+)"
                     r"(?:(?P=sfquote))")
    match = rex.match(string)
    suser_match = match.group("suser")
    return (suser_match,) if suser_match else (match.group("user"), match.group("pass"))

这可以胜任,但我强烈反对。正则表达式应尽可能简单,因为这种解决方案难以理解,因此难以维护。您可能需要一个无上下文的语法,在我看来,这更适合您作为示例提供的模式类型(特别适用于"abcdef"字符串,这需要一个单独的组。)

您的第二个问题是,即使您将其置于(?:...)内,也会捕获符号组。这就是为什么我认为检索它们更容易,然后用匹配的符号组创建元组。

答案 2 :(得分:1)

为什么要检索所有组?只需拿走你感兴趣的那些而忽略其余部分。这是一个例子:

rex = re.compile(
    r"""^(?:
      (?P<fquote>['"])
      (?P<user1>(?:(?!(?P=fquote)).)+)
      (?P=fquote)
      |
      (?P<user2>[^:"'\s]+)
    )
    (?:
      :
      (?:
        (?P<squote>['"])
        (?P<pass1>(?:(?!(?P=squote)).)+)
        (?P=squote)
        |
        (?P<pass2>[^:"'\s]+)
      )
    )?
    $""", 
    re.VERBOSE)

result = rex.sub(r"\g<user1>\g<user2> : \g<pass1>\g<pass2>", subject)

附加说明:

  • 拆分它以分别处理引用和未引用的字段使得工作变得更加容易。你知道每对组中的一组总是空的,所以连接它们是安全的。

  • (?:(?!(?P=fquote)).)+一次消耗一个字符,但只有在确认该字符与开头引号不同之后才会消耗。您不必担心它会超出收尾报价,就像.+那样。 (你真的应该在那里使用一个不情愿的.+?,但这样做会更好。)