Como usar grupos de captura regex em Python

PythonBeginner
Pratique Agora

Introdução

As capturas de grupos de expressões regulares são ferramentas poderosas em Python para extrair e manipular dados textuais. Neste laboratório, você aprenderá as técnicas essenciais para usar grupos de captura, fornecendo insights práticos sobre como esses mecanismos avançados de correspondência de padrões podem simplificar a análise de strings complexas e tarefas de extração de dados.

Noções Básicas de Captura de Grupos em Regex

Grupos de captura são um recurso poderoso em expressões regulares que permite extrair e agrupar partes específicas de um padrão correspondente. Em Python, eles são definidos usando parênteses () dentro de um padrão regex.

Vamos começar criando um script Python para demonstrar o uso básico de grupos de captura.

Abra o terminal integrado no WebIDE e navegue até o diretório do projeto, caso você ainda não esteja lá.

cd ~/project

Crie um novo arquivo chamado basic_capture.py usando o comando touch.

touch basic_capture.py

Abra basic_capture.py no editor WebIDE e adicione o seguinte 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.")

Salve o arquivo.

Agora, execute o script usando o comando python.

python basic_capture.py

Você deve ver a seguinte saída:

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

Esta saída mostra que o script extraiu com sucesso as diferentes partes do endereço de e-mail usando grupos de captura.

Você também pode acessar todos os grupos capturados como uma tupla usando o método groups(). Modifique o arquivo basic_capture.py para incluir as seguintes linhas após o bloco if match::

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

Salve o arquivo e execute o script novamente.

python basic_capture.py

A saída agora incluirá a tupla de todos os grupos capturados:

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

Isso demonstra como usar grupos de captura básicos e acessar os dados capturados.

Grupos de Captura Nomeados

Grupos de captura nomeados fornecem uma maneira mais legível de acessar dados capturados, atribuindo um nome a cada grupo. A sintaxe para um grupo de captura nomeado é (?P<name>...).

Vamos criar um novo script Python para demonstrar grupos de captura nomeados.

Crie um novo arquivo chamado named_capture.py no diretório ~/project.

touch ~/project/named_capture.py

Abra named_capture.py no editor WebIDE e adicione o seguinte 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.")

Salve o arquivo.

Execute o script usando o comando python.

python ~/project/named_capture.py

Você deve ver a seguinte saída:

Product: Laptop, Price: $999.99

Esta saída mostra que o script extraiu com sucesso o nome do produto e o preço usando grupos de captura nomeados. Você pode acessar os dados capturados usando o nome do grupo como uma chave no método group().

Grupos de captura nomeados tornam seus padrões regex e o código subsequente mais compreensíveis, especialmente para padrões complexos com muitos grupos de captura.

Uso Prático de Grupos de Captura

Grupos de captura são amplamente utilizados para extração de dados de vários formatos de texto, como arquivos de log, URLs e dados estruturados.

Vamos criar um script para analisar uma entrada de log usando grupos de captura.

Crie um novo arquivo chamado log_parser.py no diretório ~/project.

touch ~/project/log_parser.py

Abra log_parser.py no editor WebIDE e adicione o seguinte 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.")

Salve o arquivo.

Execute o script usando o comando python.

python ~/project/log_parser.py

Você deve ver a seguinte saída:

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

Este script analisou com sucesso a entrada de log e extraiu a data, hora, nível de log e mensagem usando grupos de captura.

Outro caso de uso comum é a extração de informações de URLs. Crie um novo arquivo chamado url_parser.py no diretório ~/project.

touch ~/project/url_parser.py

Abra url_parser.py e adicione o seguinte 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.")

Salve o arquivo.

Execute o script.

python ~/project/url_parser.py

A saída mostrará os componentes analisados das URLs:

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

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

Estes exemplos demonstram a aplicação prática de grupos de captura na extração de dados estruturados de texto.

Técnicas Avançadas de Grupos de Captura

Além dos grupos de captura básicos, as expressões regulares (regex) em Python oferecem recursos mais avançados, como grupos de captura aninhados, grupos não capturantes e lookarounds.

Grupos de Captura Aninhados

Grupos de captura podem ser aninhados dentro de outros grupos de captura para extrair informações mais granulares.

Crie um novo arquivo chamado nested_capture.py no diretório ~/project.

touch ~/project/nested_capture.py

Abra nested_capture.py e adicione o seguinte 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.")

Salve o arquivo.

Execute o script.

python ~/project/nested_capture.py

A saída mostrará os dados extraídos, incluindo o nome completo e seus componentes:

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

Aqui, ((\w+)\s(\w+)) é um grupo de captura aninhado. group(1) captura todo o "John Doe", group(2) captura "John" e group(3) captura "Doe". group(4) captura o ID.

Grupos Não Capturantes

Às vezes, você precisa agrupar partes de um padrão para aplicar quantificadores ou alternativas, mas não precisa capturar o conteúdo. Grupos não capturantes (?:...) são usados para essa finalidade.

Crie um novo arquivo chamado non_capturing.py no diretório ~/project.

touch ~/project/non_capturing.py

Abra non_capturing.py e adicione o seguinte 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}")

Salve o arquivo.

Execute o script.

python ~/project/non_capturing.py

A saída mostrará os nomes de domínio extraídos:

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

Neste exemplo, (?:www\.)? corresponde a "www." se existir, mas não o captura, então group(1) captura diretamente o nome do domínio.

Usar grupos não capturantes pode melhorar ligeiramente o desempenho e mantém os índices de grupo capturados mais limpos quando você só precisa capturar partes específicas de um padrão maior.

Resumo

Neste laboratório, você aprendeu como usar grupos de captura de expressões regulares (regex) em Python. Você começou com grupos de captura básicos, depois explorou grupos de captura nomeados para melhor legibilidade. Você também praticou o uso de grupos de captura para tarefas práticas de extração de dados, como análise de arquivos de log e URLs. Finalmente, você foi apresentado a técnicas avançadas como grupos aninhados e não capturantes. Ao dominar esses conceitos, você pode efetivamente extrair e manipular partes específicas de dados de texto usando expressões regulares em Python.