Comment utiliser les groupes de capture (capture groups) des expressions régulières (regex) en Python

PythonBeginner
Pratiquer maintenant

Introduction

Les groupes de capture d'expressions régulières (regular expression capture groups) sont des outils puissants en Python pour extraire et manipuler des données textuelles. Dans ce labo, vous apprendrez les techniques essentielles d'utilisation des groupes de capture, en fournissant des informations pratiques sur la façon dont ces mécanismes avancés de correspondance de motifs (pattern matching) peuvent simplifier les tâches complexes d'analyse de chaînes de caractères (string parsing) et d'extraction de données.

Bases des Groupes de Capture Regex (Regex Capture Groups)

Les groupes de capture sont une fonctionnalité puissante des expressions régulières (regular expressions) qui vous permettent d'extraire et de regrouper des parties spécifiques d'un motif correspondant (matched pattern). En Python, ils sont définis à l'aide de parenthèses () dans un motif regex.

Commençons par créer un script Python pour démontrer l'utilisation de base des groupes de capture.

Ouvrez le terminal intégré dans le WebIDE et accédez au répertoire du projet si vous n'y êtes pas déjà.

cd ~/project

Créez un nouveau fichier nommé basic_capture.py à l'aide de la commande touch.

touch basic_capture.py

Ouvrez basic_capture.py dans l'éditeur WebIDE et ajoutez le code Python suivant :

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.")

Enregistrez le fichier.

Maintenant, exécutez le script à l'aide de la commande python.

python basic_capture.py

Vous devriez voir la sortie suivante :

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

Cette sortie montre que le script a réussi à extraire les différentes parties de l'adresse e-mail à l'aide de groupes de capture.

Vous pouvez également accéder à tous les groupes capturés sous forme de tuple à l'aide de la méthode groups(). Modifiez le fichier basic_capture.py pour inclure les lignes suivantes après le bloc if match: :

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

Enregistrez le fichier et exécutez à nouveau le script.

python basic_capture.py

La sortie inclura désormais le tuple de tous les groupes capturés :

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

Cela montre comment utiliser les groupes de capture de base et accéder aux données capturées.

Groupes de Capture Nommés (Named Capture Groups)

Les groupes de capture nommés offrent une manière plus lisible d'accéder aux données capturées en attribuant un nom à chaque groupe. La syntaxe pour un groupe de capture nommé est (?P<name>...).

Créons un nouveau script Python pour démontrer les groupes de capture nommés.

Créez un nouveau fichier nommé named_capture.py dans le répertoire ~/project.

touch ~/project/named_capture.py

Ouvrez named_capture.py dans l'éditeur WebIDE et ajoutez le code Python suivant :

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.")

Enregistrez le fichier.

Exécutez le script à l'aide de la commande python.

python ~/project/named_capture.py

Vous devriez voir la sortie suivante :

Product: Laptop, Price: $999.99

Cette sortie montre que le script a réussi à extraire le nom du produit et le prix à l'aide de groupes de capture nommés. Vous pouvez accéder aux données capturées en utilisant le nom du groupe comme clé dans la méthode group().

Les groupes de capture nommés rendent vos motifs regex (regex patterns) et le code qui en découle plus compréhensibles, en particulier pour les motifs complexes avec de nombreux groupes de capture.

Utilisation Pratique des Groupes de Capture (Practical Capture Group Usage)

Les groupes de capture sont largement utilisés pour l'extraction de données à partir de divers formats de texte tels que les fichiers journaux (log files), les URL et les données structurées.

Créons un script pour analyser une entrée de journal à l'aide de groupes de capture.

Créez un nouveau fichier nommé log_parser.py dans le répertoire ~/project.

touch ~/project/log_parser.py

Ouvrez log_parser.py dans l'éditeur WebIDE et ajoutez le code Python suivant :

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.")

Enregistrez le fichier.

Exécutez le script à l'aide de la commande python.

python ~/project/log_parser.py

Vous devriez voir la sortie suivante :

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

Ce script a réussi à analyser l'entrée de journal et à extraire la date, l'heure, le niveau de journalisation (log level) et le message à l'aide de groupes de capture.

Un autre cas d'utilisation courant est l'extraction d'informations à partir d'URL. Créez un nouveau fichier nommé url_parser.py dans le répertoire ~/project.

touch ~/project/url_parser.py

Ouvrez url_parser.py et ajoutez le code suivant :

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.")

Enregistrez le fichier.

Exécutez le script.

python ~/project/url_parser.py

La sortie affichera les composants analysés des URL :

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

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

Ces exemples démontrent l'application pratique des groupes de capture dans l'extraction de données structurées à partir de texte.

Techniques Avancées des Groupes de Capture (Advanced Capture Group Techniques)

Au-delà des groupes de capture de base, les expressions régulières (regex) Python offrent des fonctionnalités plus avancées telles que les groupes de capture imbriqués, les groupes non-capturants et les assertions (lookarounds).

Groupes de Capture Imbriqués (Nested Capture Groups)

Les groupes de capture peuvent être imbriqués dans d'autres groupes de capture pour extraire des informations plus granulaires.

Créez un nouveau fichier nommé nested_capture.py dans le répertoire ~/project.

touch ~/project/nested_capture.py

Ouvrez nested_capture.py et ajoutez le code suivant :

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.")

Enregistrez le fichier.

Exécutez le script.

python ~/project/nested_capture.py

La sortie affichera les données extraites, y compris le nom complet et ses composantes :

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

Ici, ((\w+)\s(\w+)) est un groupe de capture imbriqué. group(1) capture l'ensemble de "John Doe", group(2) capture "John" et group(3) capture "Doe". group(4) capture l'ID.

Groupes Non-Capturants (Non-Capturing Groups)

Parfois, vous devez regrouper des parties d'un motif pour appliquer des quantificateurs ou des alternatives, mais vous n'avez pas besoin de capturer le contenu. Les groupes non-capturants (?:...) sont utilisés à cette fin.

Créez un nouveau fichier nommé non_capturing.py dans le répertoire ~/project.

touch ~/project/non_capturing.py

Ouvrez non_capturing.py et ajoutez le code suivant :

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}")

Enregistrez le fichier.

Exécutez le script.

python ~/project/non_capturing.py

La sortie affichera les noms de domaine extraits :

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

Dans cet exemple, (?:www\.)? correspond à "www." s'il existe, mais ne le capture pas, de sorte que group(1) capture directement le nom de domaine.

L'utilisation de groupes non-capturants peut légèrement améliorer les performances et maintient les indices des groupes capturés plus propres lorsque vous n'avez besoin de capturer que des parties spécifiques d'un motif plus large.

Résumé (Summary)

Dans ce labo, vous avez appris à utiliser les groupes de capture (capture groups) des expressions régulières (regex) en Python. Vous avez commencé avec les groupes de capture de base, puis exploré les groupes de capture nommés (named capture groups) pour une meilleure lisibilité. Vous avez également pratiqué l'utilisation des groupes de capture pour des tâches pratiques d'extraction de données telles que l'analyse de fichiers journaux (log files) et d'URL. Enfin, vous avez été initié aux techniques avancées telles que les groupes imbriqués (nested groups) et non-capturants (non-capturing groups). En maîtrisant ces concepts, vous pouvez extraire et manipuler efficacement des parties spécifiques de données textuelles à l'aide d'expressions régulières en Python.