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

18

En una expresión regular de Python, me encuentro con este problema singular. ¿Podría dar instrucciones sobre las diferencias entre re.findall('(ab|cd)', string)y 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)

La salida real es:

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

Estoy confundido en cuanto a por qué el segundo resultado no contiene 'ab'también?

rock
fuente
re.findall ('(ab | cd)', string) obtiene ['ab', 'cd'] re.findall ('(ab | cd) +', string) obtiene ['cd']
rock

Respuestas:

15

+es un cuantificador de repetición que coincide una o más veces. En la expresión regular (ab|cd)+, está repitiendo el grupo de captura (ab|cd) con +. Esto solo capturará la última iteración.

Puede razonar sobre este comportamiento de la siguiente manera:

Digamos que su cadena es abcdlay regex es (ab|cd)+. El motor Regex encontrará una coincidencia para el grupo entre las posiciones 0 y 1 a medida que absale del grupo de captura. Luego ve el +cuantificador e intenta capturar el grupo nuevamente y capturará cdentre las posiciones 2 y 3.


Si desea capturar todas las iteraciones, debe capturar el grupo repetitivo con el ((ab|cd)+)que coincide abcdy cd. Puede hacer que el grupo interno no se capture ya que no nos interesan las coincidencias de grupo interno con las ((?:ab|cd)+)que coincideabcd

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

De los documentos,

Digamos que desea hacer coincidir una etiqueta como !abc!o !123!. Solo estos dos son posibles, y desea capturar abco 123averiguar qué etiqueta tiene. Eso es bastante fácil: !(abc|123)!hará el truco.

Ahora digamos que la etiqueta puede contener múltiples secuencias de abcy 123, como !abc123!o !123abcabc!. La solución rápida y fácil es !(abc|123)+!. Esta expresión regular coincidirá con estas etiquetas. Sin embargo, ya no cumple con nuestro requisito de capturar la etiqueta de la etiqueta en el grupo de captura. Cuando esta expresión regular coincide !abc123!, el grupo de captura solo almacena 123. Cuando coincide !123abcabc!, solo se almacena abc.

Shashank V
fuente
¿Puedes vincular a algún documento dejando en claro el hecho de que + solo captura la última iteración, y qué es un grupo de captura?
Gulzar
1
@Gulzar, actualizó la respuesta. Puede leer sobre los grupos de captura aquí - regular-expressions.info/refcapture.html
Shashank V
@Shashank, gracias, tu respuesta es exactamente lo que necesito. sinceramente gracias
rock
@rock Acepta la respuesta si resolvió tu pregunta.
Shashank V
No es necesario rodear toda la expresión regular con paréntesis. Solo '(?:ab|cd)+'funcionará.
Dukeling
5

No sé si esto aclarará más las cosas, pero tratemos de imaginar lo que sucede debajo del capó de una manera simple, vamos a resumir lo que sucede usando el partido

   # 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

findallunir y consumir la cadena al mismo tiempo, imaginemos qué sucede con 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']  

Ahora lo mismo con '(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 esto aclare un poco las cosas.

Charif DZ
fuente
0

Entonces, para mí una parte confusa fue el hecho de que

Si uno o más grupos están presentes en el patrón, devuelva una lista de grupos;

docs

por lo que te devuelve no una coincidencia completa sino solo una captura. Si hace que este grupo no se capture (re.findall('(?:ab|cd)+', string), volverá ["abcd"]como esperaba inicialmente

RiaD
fuente
no estoy seguro de lo que esperabas o no
RiaD