Python: expresión regular para hacer coincidir un bloque de texto de varias líneas

Salman Mehmood 8 octubre 2023
  1. Motivo para escribir Regex para que coincida con la cadena de varias líneas
  2. Posibles soluciones para hacer coincidir cadenas de varias líneas
Python: expresión regular para hacer coincidir un bloque de texto de varias líneas

Este artículo analiza formas de buscar un patrón específico en cadenas de varias líneas. La solución compromete varios enfoques para patrones conocidos y desconocidos y explica cómo funcionan los patrones coincidentes.

Motivo para escribir Regex para que coincida con la cadena de varias líneas

Supongamos que tenemos el siguiente bloque de texto:

Any compiled body of information is known as a data set. Depending on the situation's specifics, this may be a database or a simple array.\n
\n
IBM first used the term "data set," which meant essentially the same thing as "file," to describe a collection of related records.

Desde el bloque de texto anterior, se requiere encontrar el texto inicial, y el texto se presenta unas líneas más abajo. Es importante tener en cuenta que \n simboliza una nueva línea y no es texto literal.

Para resumir, queremos encontrar y hacer coincidir el texto en varias líneas, ignorando las líneas vacías que pueden aparecer entre el texto. En el caso del texto mencionado anteriormente, debería devolver la línea Cualquier cuerpo compilado.... y la línea IBM utilizó por primera vez el término.... en una sola consulta de expresión regular.

Posibles soluciones para hacer coincidir cadenas de varias líneas

Antes de discutir las soluciones a este problema en particular, es esencial comprender los diferentes aspectos de la API de expresiones regulares (regex), en particular los que se usan con frecuencia en la solución.

Entonces, comencemos con re.compile().

Método re.compile() de Python

re. compile() compila un patrón regex en un objeto de expresión regular que podemos usar para hacer coincidir con match(), search() y otros métodos descritos.

Una ventaja de re.compile() sobre los patrones no compilados es la reutilización. Podemos usar la expresión compilada varias veces en lugar de declarar una nueva cadena para cada patrón sin compilar.

import re as regex

pattern = regex.compile(".+World")
print(pattern.match("Hello World!"))
print(pattern.search("Hello World!"))

Producción :

<re.Match object; span=(0, 11), match='Hello World'>
<re.Match object; span=(0, 11), match='Hello World'>

Método re.search() de Python

re. search() busca una cadena en busca de una coincidencia y devuelve un objeto Coincidencia si se encuentra uno.
Si existen muchas coincidencias, devolveremos la primera instancia.

También podemos usarlo directamente sin el uso de re.compile(), aplicable cuando solo se requiere realizar una consulta.

import re as regex

print(regex.search(".+World", "Hello World!"))

Producción :

<re.Match object; span=(0, 11), match='Hello World'>

Método re.finditer() de Python

re.finditer() coincide con un patrón dentro de una cadena y devuelve un iterador que entrega objetos Coincidencia para todas las coincidencias que no se superponen.

Luego podemos usar el iterador para iterar sobre las coincidencias y realizar las operaciones necesarias; las coincidencias se ordenan de la forma en que se encuentran, de izquierda a derecha en la cadena.

import re as regex

matches = regex.finditer(r"[aeoui]", "vowel letters")
for match in matches:
    print(match)

Producción :

<re.Match object; span=(1, 2), match='o'>
<re.Match object; span=(3, 4), match='e'>
<re.Match object; span=(7, 8), match='e'>
<re.Match object; span=(10, 11), match='e'>

Método re.findall() de Python

re.findall() devuelve una lista o tupla de todas las coincidencias no superpuestas de un patrón en una cadena. Una cadena se escanea de izquierda a derecha. Y los fósforos se devuelven en el orden en que fueron descubiertos.

import re as regex

# Find all capital words
string = ",,21312414.ABCDEFGw#########"
print(regex.findall(r"[A-Z]+", string))

Producción :

['ABCDEFG']

Método re.MULTILINE de Python

Una ventaja significativa de re.MULTILINE es que permite que ^ busque patrones al comienzo de cada línea en lugar de solo al comienzo de la cadena.

Símbolos de expresiones regulares de Python

Los símbolos Regex pueden volverse bastante confusos rápidamente cuando se usan de manera compleja. A continuación se muestran algunos de los símbolos utilizados en nuestras soluciones para ayudar a comprender mejor el concepto subyacente de estos símbolos.

  • ^ afirma la posición al comienzo de una línea
  • String coincide con los caracteres (sensible a mayúsculas y minúsculas) "String" literalmente
  • . coincide con todos los caracteres (excepto los símbolos utilizados para la terminación de línea)
  • + coincide con el token dado anteriormente con la mayor frecuencia posible.
  • \n coincide con un carácter de nueva línea
  • \r coincide con un símbolo de retorno de carro (CR)
  • ? coincide con el token anterior entre 0-1 veces
  • +? coincide con el token anterior entre 1 e infinito veces, lo menos posible.
  • a-z coincide con un solo carácter en el rango entre a y z (sensible a mayúsculas y minúsculas)

Use re.compile() para hacer coincidir un bloque de texto de varias líneas en Python

Entendamos usando diferentes patrones.

Patrón 1: use re.search() para el patrón conocido

Código de ejemplo:

import re as regex

multiline_string = "Regular\nExpression"
print(regex.search(r"^Expression", multiline_string, regex.MULTILINE))

Producción :

<re.Match object; span=(8, 18), match='Expression'>

La expresión anterior primero afirma su posición al comienzo de la línea (debido a ^) y luego busca las apariciones exactas de "Expression".

El uso de la marca MULTILINE garantiza que cada línea se compruebe en busca de ocurrencias de "Expression" en lugar de solo la primera línea.

Patrón 2: Usa re.search() para Patrón Desconocido

Código de ejemplo:

import re as regex

data = """Any compiled body of information is known as a data set. Depending on the situation's specifics, this may be a database or a simple array.\n
\n
IBM first used the term "data set," which meant essentially the same thing as "file," to describe a collection of related records.
"""

result = regex.compile(r"^(.+)(?:\n|\r\n)+((?:(?:\n|\r\n?).+)+)", regex.MULTILINE)

print(result.search(data)[0].replace("\n", ""))

Producción :

Any compiled body of information is known as a data set. Depending on the situation's specifics, this may be a database or a simple array.IBM first used the term "data set," which meant essentially the same thing as "file," to describe a collection of related records.

La expresión regular se puede dividir y simplificar en partes más pequeñas para una mejor legibilidad:

En el primer grupo de captura (.+), cada carácter se empareja en la línea (excepto los símbolos correspondientes a los terminadores de línea); este proceso se realiza con la mayor frecuencia posible.

Después de lo cual, en el grupo de no captura (?:\n|\r\n), solo un terminador de línea o un terminador de línea y un retorno de carro se hacen coincidir tantas veces como sea posible.

En cuanto al segundo grupo de captura ((?:(?:\n|\r\n?).+)+), consiste en un grupo de no captura ((?:(?:\n|\r\n?).+)+) ya sea un carácter de nueva línea o un carácter de nueva línea y un retorno de carro coinciden por un máximo de una vez.

Todos los caracteres coinciden fuera del grupo que no captura, excepto los terminadores de línea. Este procedimiento se realiza tantas veces como sea posible.

Patrón 3: Usa re.finditer() para Patrón Desconocido

Código de ejemplo:

import re as regex

data = """Regex In Python

Regex is a feature available in all programming languages used to find patterns in text or data.
"""

query = regex.compile(r"^(.+?)\n([\a-z]+)", regex.MULTILINE)

for match in query.finditer(data):
    topic, content = match.groups()
    print("Topic:", topic)
    print("Content:", content)

Producción :

Topic: Regex In Python
Content: 
Regex is a feature available in all programming languages used to find patterns in text or data.

La expresión anterior se puede explicar de la siguiente manera:

En el primer grupo de captura (.+?), todos los caracteres coinciden (excepto los terminadores de línea, como antes) lo menos posible. Después de lo cual, se hace coincidir un solo carácter de nueva línea \n.

Después de hacer coincidir el carácter de nueva línea, se realizan las siguientes operaciones en el segundo grupo de captura (\n[a-z ]+). Primero, se hace coincidir un carácter de nueva línea, seguido de caracteres coincidentes entre a-z tantas veces como sea posible.

Use re.findall() para hacer coincidir un bloque de texto de varias líneas en Python

Código de ejemplo:

import re as regex

data = """When working with regular expressions, the sub() function of the re library is an invaluable tool.

the subroutine looks over the string for the given pattern and applies the given replacement to all instances where it is found.
"""

query = regex.findall("([^\n\r]+)[\n\r]([a-z \n\r]+)", data)

for results in query:
    for result in results:
        print(result.replace("\n", ""))

Producción :

When working with regular expressions, the sub() function of the re library is an invaluable tool.
the subroutine looks over the string for the given pattern and applies the given replacement to all instances where it is found

Para comprender mejor la explicación de expresiones regulares, analicemos cada grupo y veamos qué hace cada parte.

En el primer grupo de captura ([^\n\r]+), todos los caracteres coinciden, excepto un símbolo de nueva línea o un carácter de retorno de carro, con la mayor frecuencia posible.

Después de eso, se realizan coincidencias cuando un carácter es un retorno de carro o una nueva línea en la expresión [\n\r].

En el segundo grupo de captura ([a-z \n\r]+), los caracteres entre a-z o una nueva línea o un retorno de carro se combinan tantas veces como sea posible.

Salman Mehmood avatar Salman Mehmood avatar

Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.

LinkedIn

Artículo relacionado - Python Regex