以下の内容はhttps://pydocument.hatenablog.com/entry/2023/03/20/000824より取得しました。


Pythonの正規表現: reモジュールの使い方とサンプルコード

Pythonで文字列のパターンマッチング、検索、置換を行うには、reモジュールを使用します。正規表現は、複雑な文字列処理を簡潔に記述できるツールですが、適切に利用するためには基本的な文法とreモジュールの使い方を理解する必要があります。この正規表現reモジュールの基本的な使い方とメールアドレスのバリデーション、キーワードによるログの抽出など具体的な使い方・サンプルコードを紹介します。

reモジュールの基本的な使い方

まずはじめに、reモジュールをインポートします。

import re

マッチングの確認: re.search()

re.search()関数は、文字列内にパターンにマッチする部分があるかを調べます。マッチする場合はMatchオブジェクトを返し、マッチしない場合はNoneを返します。

サンプルコード

# シンプルなマッチング
text = "The quick brown fox jumps over the lazy dog."
pattern = r"fox"  # "fox"という文字列にマッチするパターン

match = re.search(pattern, text)

if match:
    print("マッチしました:", match.group(0))  # マッチした部分全体を表示
else:
    print("マッチしませんでした")

re.search()は文字列全体を検索し、最初に見つかったマッチを返します。

文字列の置換: re.sub()

re.sub()関数は、パターンにマッチする部分を別の文字列に置換します。

サンプルコード

# シンプルな置換
text = "The cat is on the mat."
pattern = r"cat"  # "cat"という文字列にマッチ
replacement = "dog"  # "dog"に置換

new_text = re.sub(pattern, replacement, text)
print(new_text)  # The dog is on the mat.

マッチした部分の取得: Matchオブジェクト

re.search()re.match()が返すMatchオブジェクトからは、マッチに関する様々な情報を取り出せます。

  • group(): マッチした部分文字列全体、または指定したグループの文字列を取得します。
  • groups(): マッチした部分文字列をグループごとにタプルで取得します。
  • start(): マッチした部分文字列の開始位置を取得します。
  • end(): マッチした部分文字列の終了位置を取得します。

サンプルコード

# 電話番号の抽出 (グループ化)
pattern = r"(\d{2,4})-(\d{2,4})-(\d{4})" # 市外局番-市内局番-番号
text = "私の電話番号は03-1234-5678です。"

match = re.search(pattern, text)

if match:
    print("電話番号全体:", match.group(0))
    print("市外局番:", match.group(1))
    print("市内局番:", match.group(2))
    print("番号:", match.group(3))
    print("すべてのグループ:", match.groups())

主要な正規表現のメタ文字

正規表現では、特殊な記号(メタ文字)を使って、複雑なパターンを表現します。

メタ文字 説明
. 任意の一文字(改行を除く) a.b
^ 文字列の先頭 ^abc
$ 文字列の末尾 xyz$
* 直前の文字の0回以上の繰り返し ab*c
+ 直前の文字の1回以上の繰り返し ab+c
? 直前の文字の0回または1回の出現 ab?c
[ ] 文字クラス。カッコ内のいずれかの1文字 [a-z]
[^ ] 文字クラスの否定。カッコ内の文字以外の1文字 [^0-9]
| いずれかのパターン cat|dog
( ) グループ化。グループは後方参照やMatchオブジェクトから個別にアクセスできる (abc){2}
\d 数字 \d{3}(3桁の数字)
\w 英数字とアンダースコア [a-zA-Z0-9_] \w+
\s 空白文字(スペース、タブ、改行など) \s+
{n,m} 直前の文字のn回以上m回以下の繰り返し a{2,4}
\ メタ文字をエスケープする \. (ドットそのもの)

文字クラスの詳細

[ ] (文字クラス)を使うと、特定の文字集合のいずれか1文字にマッチさせることができます。

  • [abc]: 'a', 'b', 'c' のいずれか
  • [a-z]: a から z までのアルファベット小文字
  • [0-9]: 数字
  • [a-zA-Z0-9]: 英数字

文字クラス内で ^ を使うと、指定した文字集合以外の文字にマッチします。

  • [^0-9]: 数字以外の文字

正規表現の具体例

メールアドレスのバリデーション (簡易版)

完璧なメールアドレスのバリデーションは非常に複雑ですが、簡易的には下記のような正規表現のパターンで可能です。

pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"

HTMLタグの属性値の取得

HTMLから特定の情報を抽出することにも利用可能です。下記の例はHTMLタグののsrc属性を検索するパターンです。

pattern = r'<[^>]+src="([^"]+)"'
  • <: HTMLタグの開始
  • [^>]+ : 閉じタグ>以外の文字が1文字以上続く
  • src=": src属性を検索
  • ([^"]+): "で囲まれた内容をキャプチャするためのグループ。[^"]+"以外の文字が1つ以上続くことを表す
  • ": 属性値の終了

サンプルコード

import re
html = '<img src="image1.jpg"> <img src="image2.png">'
pattern = r'<[^>]+src="([^"]+)"'
matches = re.findall(pattern, html)
print(matches)  # 出力: ['image1.jpg', 'image2.png']

日付の抽出

日付の抽出もよくあるユースケースです。以下は、YYYY-MM-DD 形式に合致するパターンです。

pattern = r"\d{4}-\d{2}-\d{2}"
  • \d{4}: 4桁の数字(年)
  • -: 年、月、日を区切るハイフン
  • \d{2}: 2桁の数字(月)
  • -: 月、日を区切るハイフン
  • \d{2}: 2桁の数字(日)

テキスト内から日付を抽出するサンプルコード

import re
text = "イベントは2024-03-15に開催され、締め切りは2024-03-01です。"
pattern = r"\d{4}-\d{2}-\d{2}"
dates = re.findall(pattern, text)
print(dates)  # 出力: ['2024-03-15', '2024-03-01']

特定の単語を含む行を抽出(ログの解析など)

ログの解析などでは、特定のメッセージ、用語を含む行を抽出したいというケースが多々あります。

pattern = r"^.*error.*$"
  • ^: 行の先頭
  • .*: 任意の一文字が0回以上
  • error: errorという文字列
  • .*: 任意の一文字が0回以上
  • $: 行の末尾

errorという文字がある行を抽出するサンプルコード

import re
text = """
info: this is log
error: file not found
debug: this code is 100
"""
pattern = r"^.*error.*$"
result = re.findall(pattern, text, re.MULTILINE)
print(result) # ['error: file not found']

より高度な正規表現

re.findall()

re.findall()は、文字列中でパターンにマッチするすべての部分をリストで返します。

サンプルコード

text = "apple, banana, orange, apple, grape"
pattern = r"apple"
matches = re.findall(pattern, text)
print(matches)  # ['apple', 'apple']

re.split()

re.split()はパターンにマッチする部分で文字列を分割しリストにします。

サンプルコード

text = "apple, banana, orange, grape"
pattern = r",\s*"  # カンマとそれに続く空白(0個以上)
result = re.split(pattern, text)
print(result)  # ['apple', 'banana', 'orange', 'grape']

先読み・後読み (Lookahead/Lookbehind)

特定のパターンにマッチする部分の前後の文字列に基づいてマッチを行う、より高度な正規表現のテクニックです。

  • 肯定先読み (?=...): ...にマッチする部分の直前にある文字列にマッチ。
  • 否定先読み (?!...): ...にマッチしない部分の直前にある文字列にマッチ。
  • 肯定後読み (?<=...): ...にマッチする部分の直後にある文字列にマッチ。
  • 否定後読み (?<!...): ...にマッチしない部分の直後にある文字列にマッチ。

サンプルコード

# 例: 数字に続く"円"という文字列がある場合に、その数字だけを抽出
text = "これは1000円です。あれは5000円です。"
pattern = r"\d+(?=円)"  # 肯定先読みを使用
matches = re.findall(pattern, text)
print(matches) # ['1000', '5000']

raw文字列 (r"")

Pythonの文字列リテラルでは、\特殊文字エスケープシーケンス)を表すために使われます。正規表現パターンでも\を使うため、バックスラッシュ自体をマッチさせたい場合に、エスケープの重複が発生することがあります。

raw文字列を使うと、文字列中の\を特別扱いせず、そのままの文字として扱えます。正規表現パターンを記述する際は、raw文字列を使うことが推奨されます。

サンプルコード

# raw文字列を使わない場合 (バックスラッシュをエスケープする必要がある)
pattern = "\\\\section"

# raw文字列を使う場合 (エスケープが不要)
pattern = r"\\section"

まとめ

Pythonreモジュールは、正規表現による強力な文字列処理を提供します。基本的なメタ文字とreモジュールの関数を組み合わせることで、様々な文字列操作を行えます。正規表現は、最初は難しく感じるかもしれませんが、使いこなせるようになると非常に便利です。




以上の内容はhttps://pydocument.hatenablog.com/entry/2023/03/20/000824より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14