re.findall ('(ab | cd)', строка) против re.findall ('(ab | cd) +', строка) - PullRequest
18 голосов
/ 07 января 2020

В регулярном выражении 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)

Фактический результат:

['ab', 'cd']
['cd']

Я не понимаю, почему второй результат не не содержит 'ab', а?

Ответы [ 3 ]

15 голосов
/ 07 января 2020

+ является повторным квантификатором, который совпадает один или несколько раз. В регулярном выражении (ab|cd)+ вы повторяете группу захвата (ab|cd), используя +. Это будет захватывать только последнюю итерацию.

Вы можете рассуждать об этом поведении следующим образом:

Скажите, что ваша строка abcdla и регулярное выражение (ab|cd)+. Движок Regex найдет совпадение для группы между позициями 0 и 1 как ab и выйдет из группы захвата. Затем он видит квантификатор + и пытается снова захватить группу и захватывает cd между позициями 2 и 3.


Если вы хотите захватить все итерации, вы должны перехватить повторяющаяся группа вместо ((ab|cd)+), которая соответствует abcd и cd. Вы можете запретить захват внутренней группы, поскольку нам не нужны совпадения внутренних групп с ((?:ab|cd)+), что соответствует abcd

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

С документы,

Допустим, вы хотите сопоставить тег, такой как !abc! или !123!. Возможны только эти два, и вы хотите захватить abc или 123, чтобы выяснить, какой тег у вас есть. Это достаточно просто: !(abc|123)! сработает.

Теперь предположим, что тег может содержать несколько последовательностей abc и 123, например !abc123! или !123abcabc!. Быстрое и простое решение - !(abc|123)+!. Это регулярное выражение действительно будет соответствовать этим тегам. Однако это больше не отвечает нашему требованию о включении метки тега в группу захвата. Когда это регулярное выражение соответствует !abc123!, группа захвата хранит только 123. Когда он соответствует !123abcabc!, он хранит только abc.

5 голосов
/ 07 января 2020

Я не знаю, если это прояснит ситуацию больше, но давайте попробуем представить, что происходит под капотом, простым способом, мы собираемся суммировать то, что происходит, используя матч

   # 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

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']  

Теперь то же самое с '(ab|cd)+'

      'abcdabla' ---> 1:   match: 'abcdab' |  capture : 'ab'  | left to process:  'la'
      'la'       ---> 2:   match: '' |  capture : None  | left to process:  ''
      ---> final result :   ['ab']  

Я надеюсь, что это очищает вещь немного.

0 голосов
/ 07 января 2020

Итак, для меня запутанной частью стал тот факт, что

Если в шаблоне присутствует одна или несколько групп, вернуть список групп;

docs

, поэтому он возвращает вам не полное совпадение, а только совпадение захвата. Если вы сделаете эту группу не захватывающей (re.findall('(?:ab|cd)+', string), она вернет ["abcd"], как я изначально ожидал

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...