Cómo usar grupos de captura de expresiones regulares (regex) en Python

PythonBeginner
Practicar Ahora

Introducción

Los grupos de captura de expresiones regulares son herramientas poderosas en Python para extraer y manipular datos de texto. En este laboratorio, aprenderá las técnicas esenciales para usar los grupos de captura, proporcionando información práctica sobre cómo estos mecanismos avanzados de coincidencia de patrones (pattern matching) pueden simplificar el análisis (parsing) complejo de cadenas y las tareas de extracción de datos.

Conceptos básicos de los grupos de captura Regex (Regex Capture Groups)

Los grupos de captura son una característica poderosa en las expresiones regulares que le permiten extraer y agrupar partes específicas de un patrón coincidente (matched pattern). En Python, se definen utilizando paréntesis () dentro de un patrón regex.

Comencemos creando un script de Python para demostrar el uso básico de los grupos de captura.

Abra la terminal integrada en el WebIDE y navegue al directorio del proyecto si aún no está allí.

cd ~/project

Cree un nuevo archivo llamado basic_capture.py usando el comando touch.

touch basic_capture.py

Abra basic_capture.py en el editor WebIDE y agregue el siguiente código Python:

import re

text = "Contact email: john.doe@example.com"
pattern = r"(\w+)\.(\w+)@(\w+)\.(\w+)"

match = re.search(pattern, text)
if match:
    username = match.group(1)
    lastname = match.group(2)
    domain = match.group(3)
    tld = match.group(4)

    print(f"Username: {username}")
    print(f"Lastname: {lastname}")
    print(f"Domain: {domain}")
    print(f"TLD: {tld}")
else:
    print("No match found.")

Guarde el archivo.

Ahora, ejecute el script usando el comando python.

python basic_capture.py

Debería ver la siguiente salida:

Username: john
Lastname: doe
Domain: example
TLD: com

Esta salida muestra que el script extrajo con éxito las diferentes partes de la dirección de correo electrónico utilizando grupos de captura.

También puede acceder a todos los grupos capturados como una tupla utilizando el método groups(). Modifique el archivo basic_capture.py para incluir las siguientes líneas después del bloque if match::

    all_groups = match.groups()
    print(f"All groups: {all_groups}")

Guarde el archivo y ejecute el script nuevamente.

python basic_capture.py

La salida ahora incluirá la tupla de todos los grupos capturados:

Username: john
Lastname: doe
Domain: example
TLD: com
All groups: ('john', 'doe', 'example', 'com')

Esto demuestra cómo usar grupos de captura básicos y acceder a los datos capturados.

Grupos de captura con nombre (Named Capture Groups)

Los grupos de captura con nombre proporcionan una forma más legible de acceder a los datos capturados asignando un nombre a cada grupo. La sintaxis para un grupo de captura con nombre es (?P<name>...).

Creemos un nuevo script de Python para demostrar los grupos de captura con nombre.

Cree un nuevo archivo llamado named_capture.py en el directorio ~/project.

touch ~/project/named_capture.py

Abra named_capture.py en el editor WebIDE y agregue el siguiente código Python:

import re

text = "Product: Laptop, Price: $999.99"
pattern = r"Product: (?P<product>\w+), Price: \$(?P<price>\d+\.\d+)"

match = re.search(pattern, text)
if match:
    product = match.group('product')
    price = match.group('price')
    print(f"Product: {product}, Price: ${price}")
else:
    print("No match found.")

Guarde el archivo.

Ejecute el script usando el comando python.

python ~/project/named_capture.py

Debería ver la siguiente salida:

Product: Laptop, Price: $999.99

Esta salida muestra que el script extrajo con éxito el nombre del producto y el precio utilizando grupos de captura con nombre. Puede acceder a los datos capturados utilizando el nombre del grupo como una clave en el método group().

Los grupos de captura con nombre hacen que sus patrones regex y el código subsiguiente sean más comprensibles, especialmente para patrones complejos con muchos grupos de captura.

Uso práctico de los grupos de captura (Practical Capture Group Usage)

Los grupos de captura se utilizan ampliamente para la extracción de datos de varios formatos de texto, como archivos de registro (log files), URLs y datos estructurados.

Creemos un script para analizar una entrada de registro utilizando grupos de captura.

Cree un nuevo archivo llamado log_parser.py en el directorio ~/project.

touch ~/project/log_parser.py

Abra log_parser.py en el editor WebIDE y agregue el siguiente código Python:

import re

log_entry = '2023-06-15 14:30:45 [ERROR] Database connection failed'
pattern = r'(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)'

match = re.match(pattern, log_entry)
if match:
    date = match.group(1)
    time = match.group(2)
    log_level = match.group(3)
    message = match.group(4)

    print(f"Date: {date}")
    print(f"Time: {time}")
    print(f"Level: {log_level}")
    print(f"Message: {message}")
else:
    print("No match found.")

Guarde el archivo.

Ejecute el script usando el comando python.

python ~/project/log_parser.py

Debería ver la siguiente salida:

Date: 2023-06-15
Time: 14:30:45
Level: ERROR
Message: Database connection failed

Este script analizó con éxito la entrada de registro y extrajo la fecha, la hora, el nivel de registro (log level) y el mensaje utilizando grupos de captura.

Otro caso de uso común es la extracción de información de URLs. Cree un nuevo archivo llamado url_parser.py en el directorio ~/project.

touch ~/project/url_parser.py

Abra url_parser.py y agregue el siguiente código:

import re

def parse_url(url):
    pattern = r'(https?://)?([^/]+)(/.*)?'
    match = re.match(pattern, url)

    if match:
        protocol = match.group(1) or 'http://'
        domain = match.group(2)
        path = match.group(3) or '/'

        return {
            'protocol': protocol,
            'domain': domain,
            'path': path
        }
    return None

## Example usage
url = 'https://www.example.com/path/to/page'
parsed_url = parse_url(url)
if parsed_url:
    print(f"Protocol: {parsed_url['protocol']}")
    print(f"Domain: {parsed_url['domain']}")
    print(f"Path: {parsed_url['path']}")
else:
    print("Invalid URL format.")

url_no_protocol = 'example.org/another/path'
parsed_url_no_protocol = parse_url(url_no_protocol)
if parsed_url_no_protocol:
    print(f"\nProtocol: {parsed_url_no_protocol['protocol']}")
    print(f"Domain: {parsed_url_no_protocol['domain']}")
    print(f"Path: {parsed_url_no_protocol['path']}")
else:
    print("\nInvalid URL format.")

Guarde el archivo.

Ejecute el script.

python ~/project/url_parser.py

La salida mostrará los componentes analizados de las URLs:

Protocol: https://
Domain: www.example.com
Path: /path/to/page

Protocol: http://
Domain: example.org
Path: /another/path

Estos ejemplos demuestran la aplicación práctica de los grupos de captura en la extracción de datos estructurados del texto.

Técnicas avanzadas de grupos de captura (Advanced Capture Group Techniques)

Más allá de los grupos de captura básicos, las expresiones regulares (regex) de Python ofrecen características más avanzadas como grupos de captura anidados, grupos sin captura y lookarounds (inspecciones hacia adelante/atrás).

Grupos de captura anidados (Nested Capture Groups)

Los grupos de captura se pueden anidar dentro de otros grupos de captura para extraer información más granular.

Cree un nuevo archivo llamado nested_capture.py en el directorio ~/project.

touch ~/project/nested_capture.py

Abra nested_capture.py y agregue el siguiente código:

import re

def parse_complex_data(text):
    pattern = r'((\w+)\s(\w+))\s\[(\d+)\]'
    match = re.match(pattern, text)

    if match:
        full_name = match.group(1)
        first_name = match.group(2)
        last_name = match.group(3)
        id_number = match.group(4)

        return {
            'full_name': full_name,
            'first_name': first_name,
            'last_name': last_name,
            'id': id_number
        }
    return None

text = 'John Doe [12345]'
result = parse_complex_data(text)
if result:
    print(f"Full Name: {result['full_name']}")
    print(f"First Name: {result['first_name']}")
    print(f"Last Name: {result['last_name']}")
    print(f"ID: {result['id']}")
else:
    print("No match found.")

Guarde el archivo.

Ejecute el script.

python ~/project/nested_capture.py

La salida mostrará los datos extraídos, incluido el nombre completo y sus componentes:

Full Name: John Doe
First Name: John
Last Name: Doe
ID: 12345

Aquí, ((\w+)\s(\w+)) es un grupo de captura anidado. group(1) captura el "John Doe" completo, group(2) captura "John" y group(3) captura "Doe". group(4) captura el ID.

Grupos sin captura (Non-Capturing Groups)

A veces, necesita agrupar partes de un patrón para aplicar cuantificadores o alternativas, pero no necesita capturar el contenido. Los grupos sin captura (?:...) se utilizan para este propósito.

Cree un nuevo archivo llamado non_capturing.py en el directorio ~/project.

touch ~/project/non_capturing.py

Abra non_capturing.py y agregue el siguiente código:

import re

def extract_domain_info(url):
    ## (?:) creates a non-capturing group
    pattern = r'https?://(?:www\.)?([^/]+)'
    match = re.match(pattern, url)

    if match:
        domain = match.group(1) ## Only the domain is captured
        return domain
    return None

url1 = 'https://www.example.com/path'
domain1 = extract_domain_info(url1)
print(f"Domain from '{url1}': {domain1}")

url2 = 'http://example.org/another/path'
domain2 = extract_domain_info(url2)
print(f"Domain from '{url2}': {domain2}")

Guarde el archivo.

Ejecute el script.

python ~/project/non_capturing.py

La salida mostrará los nombres de dominio extraídos:

Domain from 'https://www.example.com/path': example.com
Domain from 'http://example.org/another/path': example.org

En este ejemplo, (?:www\.)? coincide con "www." si existe, pero no lo captura, por lo que group(1) captura directamente el nombre de dominio.

El uso de grupos sin captura puede mejorar ligeramente el rendimiento y mantiene los índices de los grupos capturados más limpios cuando solo necesita capturar partes específicas de un patrón más grande.

Resumen (Summary)

En este laboratorio, ha aprendido a usar grupos de captura de expresiones regulares (regex capture groups) en Python. Comenzó con grupos de captura básicos, luego exploró los grupos de captura con nombre (named capture groups) para una mejor legibilidad. También practicó el uso de grupos de captura para tareas prácticas de extracción de datos, como el análisis de archivos de registro (log files) y URLs. Finalmente, se le presentaron técnicas avanzadas como grupos anidados y grupos sin captura (non-capturing groups). Al dominar estos conceptos, puede extraer y manipular eficazmente partes específicas de datos de texto utilizando expresiones regulares en Python.