Re.findall devuelve una lista de tuplas que contienen las cadenas esperadas y también algo inesperado.

Estaba realizando una función findtags(text) para encontrar tags en un párrafo dado text. Cuando llamé a re.findall(tags, text) para encontrar etiquetas definidas en el texto, devuelve una lista de tuplas. Cada tupla en la lista contiene la cadena que esperaba que devolviera.

La función findtags(text) es la siguiente:

import re

def findtags(text):
    parms = '(\w+\s*=\s*"[^"]*"\s*)*'
    tags = '(<\s*\w+\s*' + parms + '\s*/?>)'
    print(re.findall(tags, text))
    return re.findall(tags, text)

testtext1 = """
My favorite website in the world is probably 
<a href="www.udacity.com">Udacity</a>. If you want 
that link to open in a <b>new tab</b> by default, you should
write <a href="www.udacity.com"target="_blank">Udacity</a>
instead!
"""

findtags(testtext1)

El resultado esperado es

['<a href="www.udacity.com">', 
 '<b>', 
 '<a href="www.udacity.com"target="_blank">']

El resultado real es

[('<a href="www.udacity.com">', 'href="www.udacity.com"'), 
 ('<b>', ''), 
 ('<a href="www.udacity.com"target="_blank">', 'target="_blank"')]
1
Lei Gao 3 oct. 2019 a las 17:21

3 respuestas

La mejor respuesta

re.findall devuelve una tupla porque tiene dos grupos de captura simplemente haga que el grupo params no capture uno usando ?::

import re

def findtags(text):
    # make this non capturing group
    parms = '(?:\w+\s*=\s*"[^"]*"\s*)*'
    tags = '(<\s*\w+\s*' + parms + '\s*/?>)'
    print(re.findall(tags, text))
    return re.findall(tags, text)

testtext1 = """
My favorite website in the world is probably 
<a href="www.udacity.com">Udacity</a>. If you want 
that link to open in a <b>new tab</b> by default, you should
write <a href="www.udacity.com"target="_blank">Udacity</a>
instead!
"""

findtags(testtext1)

SALIDA:

['<a href="www.udacity.com">', '<b>', '<a href="www.udacity.com"target="_blank">']

Otra razón es si no hay un grupo de captura re.findall devolverá el texto coincidente:

# non capturing group
parms = '(?:\w+\s*=\s*"[^"]*"\s*)*'
# no group at all
tags = '<\s*\w+\s*' + parms + '\s*/?>'
0
Charif DZ 3 oct. 2019 a las 14:53

Parece que no desea devolver las coincidencias del grupo de captura interno, por lo tanto, conviértalo en un grupo sin captura.

parms = '(?:\w+\s*=\s*"[^"]*"\s*)*'
0
benvc 3 oct. 2019 a las 14:24

De acuerdo con los documentos para re.findall:

Si uno o más grupos están presentes en el patrón, devuelve una lista de grupos ; Esta será una lista de tuplas si el patrón tiene más de un grupo. Las coincidencias vacías se incluyen en el resultado.

En su caso, las cosas entre paréntesis en parms = '(\w+\s*=\s*"[^"]*"\s*)*' es un grupo repetido, por lo que se devuelve una lista de tuplas de cadenas posiblemente vacías.

0
ForceBru 3 oct. 2019 a las 14:24
58221155