re.findall ( '(ab | cd)', 문자열) vs re.findall ( '(ab | cd) +', 문자열)


18

파이썬 정규 표현식 에서이 특이한 문제가 발생합니다. 당신의 차이점에 명령을 줄 수 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']를 얻습니다
rock

답변:


15

+는 한 번 이상 일치하는 반복 수량 자입니다. 정규식 (ab|cd)+에서 +를 사용하여 캡처 그룹 (ab|cd)반복합니다 . 마지막 반복 만 캡처합니다.

이 동작에 대해 다음과 같이 추론 할 수 있습니다.

문자열이 abcdla정규식이라고 가정하십시오 (ab|cd)+. 정규식 엔진은 위치 0과 1 사이의 그룹에 대한 일치를 찾아 ab캡처 그룹을 종료합니다. 그런 다음 +정량자를 보고 그룹을 다시 캡처하려고 시도하고 cd위치 2와 3 사이 를 캡처합니다 .


당신이 모든 반복을 캡처하려면, 당신은해야한다 반복 그룹을 캡처 로 대신 ((ab|cd)+)하는 일치 abcdcd. 우리는 내부 그룹 경기에 대해 걱정하지 않는 한 당신은 그룹 내 비 캡처를 할 수와 ((?: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.


+ 마지막 반복 만 캡처한다는 사실과 캡처 그룹이 무엇인지 명확하게하기 위해 일부 문서에 연결할 수 있습니까?
Gulzar

1
@Gulzar는 답변을 업데이트했습니다. 여기서 캡처 그룹에 대해 읽을 수 있습니다 -regular-expressions.info/refcapture.html
Shashank V

@ Shashank, 감사합니다. 귀하의 회신은 정확히 내가 필요한 것입니다. 진심으로 감사
바위

@rock 질문을 해결 한 경우 답변을 수락하십시오.
Shashank V

전체 정규 표현식을 괄호로 묶을 필요는 없습니다. 그냥 '(?:ab|cd)+'작동합니다.
Dukeling

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문자열을 일치시키고 동시에 소비합니다 '(ab|cd)'. 이 REGEX로 어떤 일이 발생하는지 상상해 봅시다 .

      '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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.