1

我需要使用 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我希望所有组匹配但不是fquoteand之后squote。我的意思是现在rex.match("'abc':'def').groups()回来了("'", "abc", "'", "def"),我只是想要("abc", "def")

有任何想法吗?

谢谢

4

3 回答 3

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',)
于 2013-03-11T16:18:45.310 回答
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)).)+一次使用一个字符,但只有在它确认该字符与开头引号不同之后。您不必担心它会超出结束报价,就像.+那样。(你真的应该在.+?那里使用不情愿的,但这种方式更好。)

于 2013-03-11T20:53:51.523 回答
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"字符串,它需要一个单独的组)。

你的第二个问题是符号组即使你把它们放在里面也会被捕获(?:...)。这就是为什么我认为检索它们更容易,然后使用匹配的符号组创建元组。

于 2013-03-11T18:03:43.380 回答