Python: Regex

Para comprobar nuestras expresiones regulares n-Line y comprobar si hace lo que queremos de forma muy visual podemos usar la URL https://regex101.com, es una web muy completa y sobre todo útil.

(...)
Coincide con cualquier expresión regular haya dentro de los paréntesis, e indica el comiendo y final de un grupo.
(?P<name>...)
Similar a paréntesis regulares, pero la sub cadena que coincida puede ser accesible vía un diccionario, siendo name la clave.

Flags más comúnmente usados, para usar multiples flags usaremos | (or).

Cuando se especifica, el carácter de patrón ^ coincide al principio de la cadena y al comienzo de cada línea (inmediatamente después de cada nueva línea "\n" y el carácter del patrón $ coincide al final de la cadena y al final de cada línea (inmediatamente antes de cada nueva línea "\n"). Por defecto, ^ coincide solo al principio de la cadena y $ solo al final de la cadena e inmediatamente antes de la línea nueva (si la hay) al final de la cadena. Corresponde a la bandera en línea (?m).
In [1]: import re

In [2]: cadena = """abc
    ...: def
    ...: ghi"""

In [3]: re.findall(r"^\w", cadena)
Out[3]: ['a']

In [4]: re.findall(r"^\w", cadena, flags = re.MULTILINE)
Out[4]: ['a', 'd', 'g']
No hace distinción entre mayúsculas y minúsculas. Corresponde a la bandera en línea (?i).
In [1]: import re

In [2]: cadena = "El Perro de mi Vecino"

In [3]: salida = re.search("perro", cadena)

In [4]: salida

In [5]: salida = re.search("perro", cadena, flags=re.I)

In [6]: salida
Out[6]: <_sre.SRE_Match object; span=(3, 8), match='Perro'>
Hace que el . coincida con cualquier carácter incluido \n (nueva línea). Sin esta bandera . coincidirá con cualquier cosa excepto una nueva línea (\n). Corresponde a la bandera en línea (?s).
In [1]: import re

In [2]: cadena = """abc
    ...: def
    ...: ghi"""

In [3]: re.findall(r".+", cadena, flags = re.DOTALL)
Out[3]: ['abc\ndef\nghi']

In [4]: re.findall(r".+", cadena)
Out[4]: ['abc', 'def', 'ghi']
Nos permite tener por separado e incluso comentados cada patrón especificado. Es importante indicar que los espacios SON ignorados por lo que si necesitamos indicar un espacio hay que escaparlo expicitamente. Corresponde a la bandera en línea (?x).
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [74]: salida =  re.search("""Software\             # ignoramos
    ...:                       \((?P<modelo>.*?)\),\  # obtenemos el modelo
    ...:                       Version\               # ignoramos
    ...:                       (?P<version>\S+),      # obtenemos versión""", cadena, flags=re.X)

In [75]: salida.groups()
Out[75]: ('C2960-LANBASE-M', '12.2(0.0.16)FX')

In [76]: salida = re.search("Software \((.*?)\), Version (\S+),", cadena)

In [77]: salida.groups()
Out[77]: ('C2960-LANBASE-M', '12.2(0.0.16)FX')
Como se puede ver, ambas expresiones regulares hacen lo mismo, pero con re.X podemos especificar comentarios.

En estos métodos el patrón se especifica siempre, con lo cual su uso es para patrones que SOLO se usan una vez.

Nos permite ejecutar una expresión regular y obtener los resultados. Podemos indicar diferentes flags uniéndolos con | (or).
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [3]: salida = re.search("Version (\S+),", cadena)

In [4]: salida
Out[4]: <_sre.SRE_Match object; span=(54, 77), match='Version 12.2(0.0.16)FX,'>
Divide una cadena (string) usando el patrón (patterm) como divisor. El valor devuelto es una lista. Si el patrón contiene paréntesis (indica grupos) en la lista demás aparecerá el patrón como elementos. maxsplit indica cuantas divisiones máximas se realizan, por defecto es 0 que no hay límite.
In [1]: import re

In [2]: re.split(r';', cadena, flags=re.M)
Out[2]: ['col1', 'col2:col3', 'col4']

In [3]: cadena = "col1;col2;col3;col4"

In [4]: re.split(r';', cadena)
Out[4]: ['col1', 'col2', 'col3', 'col4']

In [5]: re.split(r'(;)', cadena)
Out[5]: ['col1', ';', 'col2', ';', 'col3', ';', 'col4']
Devuelve una cadena nueva reemplazando las coincidencias del patrón con la cadena repl. count indica cuantas substituciones máximas se realizan, por defecto es 0 que no hay límite.
In [1]: import re

In [2]: re.sub(r';', '-', cadena)
Out[2]: 'col1-col2-col3-col4'

In [3]: re.sub(r';', '-_-', cadena)
Out[3]: 'col1-_-col2-_-col3-_-col4'

Si vamos a necesitar aplicar cierto patrón varias veces contra varias cadenas (o variables) lo mejor es compilar un patrón (ver más arriba .compile() y luego procesar esa expresión regular las veces que necesitemos, así si tenemos que modificar el patrón lo hacemos una sola vez en un solo sitio.

regex.search(string[, pos[, endpos]])

AMPLIAR

Una vez que tenemos el objeto Match podemos procesarlo y obtener información.

Devuelve 1 o más grupos de la coincidencia (match), si solo se especifica un argumento, el resultado es una cadena (str), por el contrario si se especifica más de un argumento, el resultado es un tuple. Sin argumentos asume por defecto valor 0, que muestra TODA la coincidencia (match). Si el valor especificado es un valor negativo o mayor al número de grupos existentes se produce una excepción IndexError. Si el grupo está contenido en una parte del patrón que NO ha producido una coincidencia el valor es None.
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [3]: salida = re.search("Software \((.*?)\), Version (\S+),", cadena)

In [4]: salida
Out[4]: <_sre.SRE_Match object; span=(26, 77), match='Software (C2960-LANBASE-M), Version 12.2(0.0.16)F>

In [5]: salida.group(0)
Out[5]: 'Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX,'

In [6]: salida.group(1)
Out[6]: 'C2960-LANBASE-M'

In [7]: salida.group(2)
Out[7]: '12.2(0.0.16)FX'

In [8]: salida.group(1,2)
Out[8]: ('C2960-LANBASE-M', '12.2(0.0.16)FX')

In [9]: salida.group(3)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-16-8f4901e5f76d> in <module>()
----> 1 salida.group(3)

IndexError: no such group
En este ejemplo tenemos parte de la salida del comando show version y queremos obtener el tipo de chasis y la versión, por lo que con la expresión regular Software \((.*?)\), Version (\S+), obtenemos la coincidencia (match) "Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX," que almacenamos en salida y podemos acceder mediante .group(0) (el índice 0 siempre existe y es la coincidencia encontrada). En este ejemplo como hemos usado paréntesis obtenemos grupos (al ser el primero en el índice 1). Si no hubiese paréntesis, es decir, grupos, solo existiría el indice 0.
Nos devuelve un tuple con los valores de todos los grupos (siempre desde el 1, el 0 es la coincidencia completa).
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [3]: salida = re.search("Software \((.*?)\), Version (\S+),", cadena)

In [4]: salida
Out[4]: <_sre.SRE_Match object; span=(26, 77), match='Software (C2960-LANBASE-M), Version 12.2(0.0.16)F>

In [5]: salida.groups()
Out[5]: ('C2960-LANBASE-M', '12.2(0.0.16)FX')
Es lo mismo que .group() pero necesitamos dar nombre a los grupos y nos devuelve un diccionario con los grupos usando los nombre proporcionado como claves (keys).
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [3]: salida = re.search("Software \((?P<modelo>.*?)\), Version (?P<version>\S+),", cadena)

In [4]: salida.group(0)
Out[4]: 'Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX,'

In [5]: salida.groupdict()
Out[5]: {'modelo': 'C2960-LANBASE-M', 'version': '12.2(0.0.16)FX'}
Util para saber o comparar la cadena suministrada para la expresión regular.
In [1]: import re

In [2]: cadena = "Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc."

In [3]: salida = re.search("Software \((?P<modelo>.*?)\), Version (?P<version>\S+),", cadena)

In [4]: salida.string
Out[4]: 'Cisco IOS Software, C2960 Software (C2960-LANBASE-M), Version 12.2(0.0.16)FX, CISCO DEVELOPMENT TEST VERSION Copyright (c) 1986-2005 by Cisco Systems, Inc.'

Más información en: regex

Retro

Lugares

Redes

Sistemas

Varios