Python 正则表达式贪婪问题

Python 正则表达式贪婪问题,python,regex,Python,Regex,我需要使用Python解析一个字符串,并提取两个标记,它们由:(冒号)分隔,可以用单引号、双引号或无引号括起来 工作示例: # <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) "

我需要使用Python解析一个字符串,并提取两个标记,它们由
(冒号)分隔,可以用单引号、双引号或无引号括起来

工作示例:

# <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)
#->
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,)
#->
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))")
>>重新导入
>>>rex=re.compile(r“(?P[\'\'\”])”
r“(?P+)”
r“(?P=fquote)”
r“(?:\:”
r“(?P[\'\”]?)
r“(?P+)”
r“(?P=squote)))
我有两个问题,第一个是样本案例6)和7)不起作用,第二个是在
rex.match
之后,我希望所有组都匹配,但不是
fquote
squote
组。我的意思是现在
rex.match(“'abc':'def')。groups()
返回
(“,”abc“,”def“)
,我只想
(“abc”,“def”)

有什么想法吗


谢谢

您可以在此处使用
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',)
def foo(字符串):
rex=re.compile(r“(?P[\'\'\”])”
r“(?P.+?)”
r“(?:(?P=fquote))”
r“(?:\:”
r“(?P[\'\”]?)
r“(?P+)”
r“(?P=squote))”
r“|”(?P[\'\'”]?)
r“(?P+)”
r“(?:(?P=sfquote))”)
match=rex.match(字符串)
suser_match=match.group(“suser”)
如果suser_匹配else(match.group(“用户”)、match.group(“通过”),则返回(suser_匹配)
这确实有效,但我强烈反对。正则表达式应该尽可能简单,因为这种解决方案很难理解,因此也很难维护。您可能需要一个上下文无关语法,我认为它更适合您作为示例给出的模式类型(特别是
“abcdef”
字符串,它需要一个单独的组)


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

为什么必须检索所有的组?就拿那些你感兴趣的,忽略其余的。下面是一个例子:

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)
rex=re.compile(
r“^(?)
(?P['“]))
(?(?!(?P=fquote))+)
(?P=fquote)
|
(?P[^:“'\s]+)
)
(?:
:
(?:
(?P['“]))
(?(?!(?P=squote))+)
(?P=squote)
|
(?P[^:“'\s]+)
)
)?
$""", 
关于(冗长的)
结果=rex.sub(r“\g\g:\g\g”,主题)
补充说明:

  • 将其拆分以分别处理带引号的字段和不带引号的字段可以使作业变得非常简单。您知道每对组中的一个组总是空的,所以连接它们是安全的

  • (?:(?!(?p=fquote))+
    一次使用一个字符,但仅在确认该字符与开头引号不同之后。你不必像
    +
    那样担心它超出了收盘报价。(你们真的应该在那个里使用一个勉强的
    +?
    ,但这是一种更好的方法。)


它不适用于单引号和双引号的混合。示例:s='\'abc\':“a:bc”@user1595496 Ahh-没有在您的正则表达式中发现您正在寻找的任何一个/或。。。仅以您的示例数据为例;)我只想要一个正则表达式,不使用外部模块,不过还是要谢谢你。
csv
re
更像一个外部模块吗?无论如何,我想正则表达式上瘾很难治愈
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)