Python で正規表現キャプチャグループを使う方法

PythonBeginner
オンラインで実践に進む

はじめに

正規表現のキャプチャグループは、Python でテキストデータを抽出および操作するための強力なツールです。この実験(Lab)では、キャプチャグループを使用するための不可欠なテクニックを学び、これらの高度なパターンマッチングメカニズムが、複雑な文字列解析とデータ抽出タスクをどのように簡素化できるかについて、実践的な洞察を提供します。

正規表現キャプチャグループの基本

キャプチャグループは、正規表現の強力な機能であり、一致したパターンから特定の部分を抽出してグループ化することができます。Python では、正規表現パターン内で括弧 () を使用して定義されます。

まず、基本的なキャプチャグループの使用法を示す Python スクリプトを作成しましょう。

WebIDE の統合ターミナルを開き、まだプロジェクトディレクトリに移動していない場合は移動します。

cd ~/project

touch コマンドを使用して、basic_capture.py という名前の新しいファイルを作成します。

touch basic_capture.py

WebIDE エディタで basic_capture.py を開き、次の 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.")

ファイルを保存します。

次に、python コマンドを使用してスクリプトを実行します。

python basic_capture.py

次の出力が表示されるはずです。

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

この出力は、スクリプトがキャプチャグループを使用してメールアドレスのさまざまな部分を正常に抽出したことを示しています。

groups() メソッドを使用して、キャプチャされたすべてのグループをタプルとしてアクセスすることもできます。basic_capture.py ファイルを修正して、if match: ブロックの後に次の行を追加します。

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

ファイルを保存して、スクリプトを再度実行します。

python basic_capture.py

出力には、キャプチャされたすべてのグループのタプルが含まれるようになります。

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

これは、基本的なキャプチャグループの使用方法と、キャプチャされたデータへのアクセス方法を示しています。

名前付きキャプチャグループ

名前付きキャプチャグループは、各グループに名前を割り当てることで、キャプチャされたデータに、より可読性の高い方法でアクセスできるようにします。名前付きキャプチャグループの構文は (?P<name>...) です。

名前付きキャプチャグループを示す新しい Python スクリプトを作成しましょう。

~/project ディレクトリに named_capture.py という名前の新しいファイルを作成します。

touch ~/project/named_capture.py

WebIDE エディタで named_capture.py を開き、次の 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.")

ファイルを保存します。

python コマンドを使用してスクリプトを実行します。

python ~/project/named_capture.py

次の出力が表示されるはずです。

Product: Laptop, Price: $999.99

この出力は、スクリプトが名前付きキャプチャグループを使用して製品名と価格を正常に抽出したことを示しています。group() メソッドでグループ名をキーとして使用して、キャプチャされたデータにアクセスできます。

名前付きキャプチャグループを使用すると、特に多数のキャプチャグループを持つ複雑なパターンにおいて、正規表現パターンと後続のコードがより理解しやすくなります。

実践的なキャプチャグループの使用法

キャプチャグループは、ログファイル、URL、構造化データなど、さまざまなテキスト形式からのデータ抽出に広く使用されています。

キャプチャグループを使用してログエントリを解析するスクリプトを作成しましょう。

~/project ディレクトリに log_parser.py という名前の新しいファイルを作成します。

touch ~/project/log_parser.py

WebIDE エディタで log_parser.py を開き、次の 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.")

ファイルを保存します。

python コマンドを使用してスクリプトを実行します。

python ~/project/log_parser.py

次の出力が表示されるはずです。

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

このスクリプトは、キャプチャグループを使用してログエントリを正常に解析し、日付、時刻、ログレベル、およびメッセージを抽出しました。

もう 1 つの一般的なユースケースは、URL からの情報の抽出です。~/project ディレクトリに url_parser.py という名前の新しいファイルを作成します。

touch ~/project/url_parser.py

url_parser.py を開き、次のコードを追加します。

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

ファイルを保存します。

スクリプトを実行します。

python ~/project/url_parser.py

出力には、URL の解析されたコンポーネントが表示されます。

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

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

これらの例は、テキストから構造化データを抽出する際のキャプチャグループの実用的な応用を示しています。

高度なキャプチャグループのテクニック

基本的なキャプチャグループに加えて、Python の正規表現は、ネストされたキャプチャグループ、非キャプチャグループ、先読み/後読み(lookarounds)などの、より高度な機能を提供します。

ネストされたキャプチャグループ

キャプチャグループは、より詳細な情報を抽出するために、他のキャプチャグループ内にネストできます。

~/project ディレクトリに nested_capture.py という名前の新しいファイルを作成します。

touch ~/project/nested_capture.py

nested_capture.py を開き、次のコードを追加します。

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

ファイルを保存します。

スクリプトを実行します。

python ~/project/nested_capture.py

出力には、フルネームとその構成要素を含む、抽出されたデータが表示されます。

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

ここで、((\w+)\s(\w+)) はネストされたキャプチャグループです。group(1) は "John Doe" 全体をキャプチャし、group(2) は "John" をキャプチャし、group(3) は "Doe" をキャプチャします。group(4) は ID をキャプチャします。

非キャプチャグループ

量指定子(quantifier)または選択肢(alternatives)を適用するためにパターンの部分をグループ化する必要があるが、コンテンツをキャプチャする必要がない場合があります。非キャプチャグループ (?:...) は、この目的で使用されます。

~/project ディレクトリに non_capturing.py という名前の新しいファイルを作成します。

touch ~/project/non_capturing.py

non_capturing.py を開き、次のコードを追加します。

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

ファイルを保存します。

スクリプトを実行します。

python ~/project/non_capturing.py

出力には、抽出されたドメイン名が表示されます。

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

この例では、 (?:www\.)? は "www." が存在する場合に一致しますが、キャプチャしないため、group(1) はドメイン名を直接キャプチャします。

非キャプチャグループを使用すると、パフォーマンスがわずかに向上し、より大きなパターンの特定の部分のみをキャプチャする必要がある場合に、キャプチャされたグループのインデックスをよりクリーンに保つことができます。

まとめ

この実験(Lab)では、Python で正規表現(regex)のキャプチャグループを使用する方法を学びました。基本的なキャプチャグループから始めて、可読性を向上させるための名前付きキャプチャグループを調べました。また、ログファイルや URL の解析など、実践的なデータ抽出タスクにキャプチャグループを使用する練習も行いました。最後に、ネストされたグループや非キャプチャグループなどの高度なテクニックを紹介しました。これらの概念を習得することで、Python で正規表現を使用して、テキストデータの特定の部分を効果的に抽出および操作できます。