re.findall ('(ab | cd)', рядок) vs re.findall ('(ab | cd) +', рядок)


18

У регулярному виразі 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'?


re.findall ('(ab | cd)', string) отримує ['ab', 'cd'] re.findall ('(ab | cd) +', string) отримує ['cd']
рок

Відповіді:


15

+- це кількісний коефіцієнт повторення, який відповідає одному чи більше разів. У регулярному вираженні (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.


чи можете ви зв’язатись із деяким документом, пояснюючи той факт, що + фіксує лише останню ітерацію, а що таке група захоплення?
Гульзар

1
@Gulzar, оновив відповідь. Про групи захоплення можна прочитати тут - regular-expressions.info/refcapture.html
Shashank V

@Shashank, дякую, ваша відповідь - саме те, що мені потрібно. щиро дякую
рок

@rock Будь ласка, прийміть відповідь, якщо вона вирішила ваше питання.
Шашанк V

Немає необхідності оточувати весь регекс дужками. Просто '(?:ab|cd)+'буде працювати.
Герцогство

5

Я не знаю, чи це ще більше очистить речі, але давайте спробуємо уявити, що відбувається під кришкою простим способом, ми збираємось підсумовувати те, що відбувається за допомогою матчу

   # 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

Отже, для мене заплутаною частиною було те, що

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

док

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


не впевнений, що ви також очікували чи ні
RiaD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.