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

18

Em uma expressão regular do Python, encontro esse problema singular. Você poderia dar instruções sobre as diferenças entre re.findall('(ab|cd)', string)e 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)

A saída real é:

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

Estou confuso sobre por que o segundo resultado não contém 'ab'também?

Rocha
fonte
re.findall ('(ab | cd)', string) recebe ['ab', 'cd'] re.findall ('(ab | cd) +', string) recebe ['cd']
rock

Respostas:

15

+é um quantificador de repetição que corresponde uma ou mais vezes. Na regex (ab|cd)+, você está repetindo o grupo de captura (ab|cd) usando +. Isso capturará apenas a última iteração.

Você pode argumentar sobre esse comportamento da seguinte maneira:

Digamos que sua string é abcdlae regex é (ab|cd)+. O mecanismo Regex encontrará uma correspondência para o grupo entre as posições 0 e 1 abe sai do grupo de captura. Em seguida, ele vê o +quantificador e tenta capturar o grupo novamente e captura cdentre as posições 2 e 3.


Se você deseja capturar todas as iterações, deve capturar o grupo de repetição em vez de ((ab|cd)+)quais correspondências abcde cd. Você pode fazer o grupo interno não capturar, pois não nos importamos com correspondências de grupos internos com ((?:ab|cd)+)quais correspondênciasabcd

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

No Documentos,

Digamos que você queira combinar uma tag como !abc!ou !123!. Somente esses dois são possíveis, e você deseja capturar abcou 123descobrir qual tag você obteve. Isso é fácil: !(abc|123)!fará o truque.

Agora, digamos que a tag possa conter várias seqüências de abce 123, como !abc123!ou !123abcabc!. A solução rápida e fácil é !(abc|123)+!. Essa expressão regular realmente corresponderá a essas tags. No entanto, ele não atende mais ao nosso requisito de capturar o rótulo da tag no grupo de captura. Quando esse regex corresponde !abc123!, o grupo de captura armazena apenas 123. Quando corresponde !123abcabc!, apenas armazena abc.

Shashank V
fonte
você pode vincular a um documento que esclareça o fato de que o + captura apenas a última iteração e o que é um grupo de captura?
Gulzar
11
@Gulzar, atualizou a resposta. Você pode ler sobre grupos de captura aqui - regular-expressions.info/refcapture.html
Shashank V
@ Shanks, obrigado, sua resposta é exatamente o que eu preciso. sinceramente obrigado
rock
@ rock Aceite a resposta se tiver resolvido sua pergunta.
Shashank V
Não há necessidade de cercar todo o regex entre colchetes. Apenas '(?:ab|cd)+'vai funcionar.
Dukeling
5

Não sei se isso vai esclarecer mais as coisas, mas vamos tentar imaginar o que acontece sob o capô de uma maneira simples, vamos resumir o que acontece usando 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

findallcorresponder e consumir a string ao mesmo tempo, vamos imaginar o que acontece com este 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']  

Agora a mesma coisa com '(ab|cd)+'

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

Espero que isso esclareça um pouco.

Charif DZ
fonte
0

Então, para mim, parte confusa foi o fato de que

Se um ou mais grupos estiverem presentes no padrão, retorne uma lista de grupos;

docs

portanto, não está retornando uma correspondência completa, mas apenas uma captura. Se você fizer esse grupo não capturar (re.findall('(?:ab|cd)+', string), ele retornará ["abcd"]como eu esperava inicialmente

RiaD
fonte
não tenho certeza é o que você também esperava ou não
RiaD 07/01