re.findall('(ab|cd)', string) vs re.findall('(ab|cd)+', string)

roc*_*ock 18 python regex

在 Python 正则表达式中,我遇到了这个奇异的问题。你能说明re.findall('(ab|cd)', string)和之间的区别re.findall('(ab|cd)+', string)吗?

import re

string = 'abcdla'
result = re.findall('(ab|cd)', string)
result2 = re.findall('(ab|cd)+', string)
print(result)
print(result2)
Run Code Online (Sandbox Code Playgroud)

实际输出为:

['ab', 'cd']
['cd']
Run Code Online (Sandbox Code Playgroud)

我很困惑为什么第二个结果也不包含'ab'

Sha*_*k V 16

+是匹配一次或多次的重复量词。在正则表达式中(ab|cd)+,您使用 +重复捕获组 (ab|cd)。这只会捕获最后一次迭代。

您可以对这种行为进行如下推理:

假设您的字符串是abcdla,正则表达式是(ab|cd)+. 正则表达式引擎将在位置 0 和 1 之间找到组的匹配项ab并退出捕获组。然后它看到+量词,因此尝试再次捕获该组并将cd在位置 2 和 3 之间捕获。


如果要捕获所有迭代,则应捕获重复组,而不是使用((ab|cd)+)which 匹配abcdcd。您可以使内部组不被捕获,因为我们不关心内部组匹配与((?:ab|cd)+)哪些匹配abcd

https://www.regular-expressions.info/captureall.html

从文档中,

假设您想匹配像!abc!or 之类的标签!123!。只有这两个是可能的,并且您想捕获abcor123以找出您获得的标签。这很容易:!(abc|123)!会做的伎俩。

现在假设标签可以包含多个abcand 序列123,例如!abc123!or !123abcabc!。快速简便的解决方案是 !(abc|123)+!。这个正则表达式确实会匹配这些标签。但是,它不再满足我们将标签的标签捕获到捕获组中的要求。当此正则表达式匹配时!abc123!,捕获组仅存储123. 当它匹配时!123abcabc!,它只存储abc


Cha*_* DZ 6

我不知道这是否会使事情更清楚,但让我们尝试以简单的方式想象引擎盖下发生的事情,我们将使用 match 总结发生的事情

   # group(0) return the matched string the captured groups are returned in groups or you can access them
   # using group(1), group(2).......  in your case there is only one group, one group will capture only 
   # one part so when you do this
   string = 'abcdla'
   print(re.match('(ab|cd)', string).group(0))  # only 'ab' is matched and the group will capture 'ab'
   print(re.match('(ab|cd)+', string).group(0)) # this will match 'abcd'  the group will capture only this part 'cd' the last iteration
Run Code Online (Sandbox Code Playgroud)

findall匹配并同时使用字符串让我们想象一下这个 REGEX 会发生什么'(ab|cd)'

      'abcdabla' ---> 1:   match: 'ab' |  capture : ab  | left to process:  'cdabla'
      'cdabla'   ---> 2:   match: 'cd' |  capture : cd  | left to process:  'abla'
      'abla'     ---> 3:   match: 'ab' |  capture : ab  | left to process:  'la'
      'la'       ---> 4:   match: '' |  capture : None  | left to process:  ''

      --- final : result captured ['ab', 'cd', 'ab']  
Run Code Online (Sandbox Code Playgroud)

现在同样的事情 '(ab|cd)+'

      'abcdabla' ---> 1:   match: 'abcdab' |  capture : 'ab'  | left to process:  'la'
      'la'       ---> 2:   match: '' |  capture : None  | left to process:  ''
      ---> final result :   ['ab']  
Run Code Online (Sandbox Code Playgroud)

我希望这能让事情变得更清楚一点。