こんにちは、JS2IIUです。
正規表現(Regular Expression)は、文字列の検索やパターンマッチングを行うための強力なツールです。Pythonではreモジュールを使用することで、複雑な文字列処理を効率的に実行することができます。今回もよろしくお願いします。
1. reモジュールの基本
まず最初に、reモジュールをインポートする必要があります:
import re主な関数
reモジュールには以下の重要な関数があります:
re.match(): 文字列の先頭からパターンマッチングを行うre.search(): 文字列全体からパターンを検索するre.findall(): すべてのマッチを検索してリストとして返すre.sub(): パターンマッチした部分を置換するre.split(): パターンで文字列を分割する
2. パターンマッチングの基本
2.1 単純な文字列マッチング
# 基本的な文字列マッチング
text = "Hello, Python!"
result = re.search(r"Python", text)
print(result.group()) # 出力: Python
# マッチしない場合
result = re.search(r"Java", text)
print(result) # 出力: None2.2 メタ文字の使用
# ドット(.): 任意の1文字にマッチ
text = "cat, bat, rat"
result = re.findall(r".at", text)
print(result) # 出力: ['cat', 'bat', 'rat']
# アスタリスク(*): 直前の文字の0回以上の繰り返し
text = "ca*t"
result = re.match(r"ca*t", text)
print(result.group()) # 出力: cat3. よく使用するパターン
3.1 数字のマッチング
# 数字にマッチする
text = "私の電話番号は123-4567-8901です"
result = re.search(r"\d{3}-\d{4}-\d{4}", text)
print(result.group()) # 出力: 123-4567-8901
# 数字以外にマッチする
text = "ABC123"
result = re.findall(r"\D+", text)
print(result) # 出力: ['ABC']3.2 メールアドレスのバリデーション
def is_valid_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
# テスト
print(is_valid_email("user@example.com")) # True
print(is_valid_email("invalid.email@")) # False4. グループの使用
4.1 キャプチャグループ
# 括弧()でグループを作成
text = "2024年2月19日"
pattern = r"(\d{4})年(\d{1,2})月(\d{1,2})日"
result = re.match(pattern, text)
if result:
year = result.group(1)
month = result.group(2)
day = result.group(3)
print(f"年: {year}, 月: {month}, 日: {day}")
# 出力: 年: 2024, 月: 2, 日: 194.2 名前付きグループ
# ?P<name>でグループに名前をつける
text = "名前: 山田太郎, 年齢: 30歳"
pattern = r"名前: (?P<name>.*?), 年齢: (?P<age>\d+)歳"
result = re.search(pattern, text)
if result:
print(f"名前: {result.group('name')}") # 出力: 名前: 山田太郎
print(f"年齢: {result.group('age')}") # 出力: 年齢: 305. 文字列の置換
5.1 基本的な置換
# 単純な置換
text = "Hello, World!"
result = re.sub(r"World", "Python", text)
print(result) # 出力: Hello, Python!
# 複数箇所の置換
text = "cat and cat"
result = re.sub(r"cat", "dog", text)
print(result) # 出力: dog and dog5.2 条件付き置換
def convert_case(match):
word = match.group(0)
return word.upper() if len(word) > 3 else word
text = "The cat and dog are friends"
result = re.sub(r'\w+', convert_case, text)
print(result) # 出力: THE cat and dog ARE FRIENDS6. パフォーマンスの最適化
6.1 パターンのコンパイル
頻繁に使用するパターンは、コンパイルして再利用することでパフォーマンスが向上します:
# パターンのコンパイル
pattern = re.compile(r'\d+')
# 複数回の使用
text1 = "123 456"
text2 = "789 012"
print(pattern.findall(text1)) # 出力: ['123', '456']
print(pattern.findall(text2)) # 出力: ['789', '012']6.2 最適化のヒント
- 可能な限り具体的なパターンを使用する
- 過度な後方参照を避ける
- 不要な括弧の使用を控える
- 適切なフラグを使用する(re.VERBOSE, re.IGNORECASE など)
7. よくある間違いと注意点
7.1 メタ文字のエスケープ
# 正しいエスケープ
text = "price: $100"
result = re.search(r'\$\d+', text)
print(result.group()) # 出力: $100
# ドット文字のエスケープ
text = "file.txt"
result = re.search(r'file\.txt', text)
print(result.group()) # 出力: file.txt7.2 貪欲な量指定子と非貪欲な量指定子
text = "<p>First paragraph</p><p>Second paragraph</p>"
# 貪欲なマッチング
greedy = re.findall(r'<p>.*</p>', text)
print(greedy) # 出力: ['<p>First paragraph</p><p>Second paragraph</p>']
# 非貪欲なマッチング
non_greedy = re.findall(r'<p>.*?</p>', text)
print(non_greedy) # 出力: ['<p>First paragraph</p>', '<p>Second paragraph</p>']8. 貪欲マッチングと非貪欲マッチングの詳細説明
正規表現における貪欲(greedy)マッチングと非貪欲(non-greedy)マッチングの違いを理解することは、効果的なパターンマッチングを行う上で非常に重要です。
8.1 貪欲マッチングとは
貪欲マッチングは、量指定子(*, +, ?, {n,m})がデフォルトで持つ動作で、「できるだけ多くの文字にマッチする」という特徴があります。
# 貪欲マッチングの例
text = "<h1>タイトル</h1><h2>サブタイトル</h2>"
pattern = r"<.*>"
result = re.search(pattern, text)
print(result.group())
# 出力: <h1>タイトル</h1><h2>サブタイトル</h2>
# 最初の'<'から最後の'>'まですべてマッチしてしまう8.2 非貪欲マッチングとは
非貪欲(最小)マッチングは、量指定子の後に?を付けることで実現され、「できるだけ少ない文字でマッチする」という特徴があります。
# 非貪欲マッチングの例
text = "<h1>タイトル</h1><h2>サブタイトル</h2>"
pattern = r"<.*?>"
result = re.findall(pattern, text)
print(result)
# 出力: ['<h1>', '</h1>', '<h2>', '</h2>']
# 最小限の文字数でマッチング8.3 実践的な例
HTMLタグの抽出
html = """
<div class="content">
<p>最初の段落</p>
<p>次の段落</p>
</div>
"""
# 貪欲マッチング - 意図しない結果
greedy = re.findall(r'<p>.*</p>', html)
print("貪欲マッチング:")
print(greedy)
# 出力: ['<p>最初の段落</p>\n <p>次の段落</p>']
# 非貪欲マッチング - 期待通りの結果
non_greedy = re.findall(r'<p>.*?</p>', html)
print("非貪欲マッチング:")
print(non_greedy)
# 出力: ['<p>最初の段落</p>', '<p>次の段落</p>']引用符で囲まれた文字列の抽出
text = '"First quote" some text "Second quote" more text "Third quote"'
# 貪欲マッチング - 問題のある結果
greedy = re.findall(r'".*"', text)
print("貪欲マッチング:")
print(greedy)
# 出力: ['"First quote" some text "Second quote" more text "Third quote"']
# 非貪欲マッチング - 正しい結果
non_greedy = re.findall(r'".*?"', text)
print("非貪欲マッチング:")
print(non_greedy)
# 出力: ['"First quote"', '"Second quote"', '"Third quote"']8.4 量指定子と貪欲/非貪欲の対応
各量指定子の貪欲版と非貪欲版の対応表:
# 量指定子の例
text = "aaabbaaa"
# *(0回以上)
print(re.findall(r'a*', text)) # 貪欲: ['aaa', '', '', 'aaa', '']
print(re.findall(r'a*?', text)) # 非貪欲: ['', '', '', '', '', '', '', '', '']
# +(1回以上)
print(re.findall(r'a+', text)) # 貪欲: ['aaa', 'aaa']
print(re.findall(r'a+?', text)) # 非貪欲: ['a', 'a', 'a', 'a', 'a', 'a']
# ?(0回または1回)
print(re.findall(r'ab?', text)) # 貪欲: ['a', 'ab', 'a', 'a', 'a']
print(re.findall(r'ab??', text)) # 非貪欲: ['a', 'a', 'b', 'a', 'a', 'a']
# {n,m}(n回以上m回以下)
print(re.findall(r'a{1,3}', text)) # 貪欲: ['aaa', 'aaa']
print(re.findall(r'a{1,3}?', text)) # 非貪欲: ['a', 'a', 'a', 'a', 'a', 'a']8.5 実装上の注意点
- パフォーマンスの考慮
- 非貪欲マッチングは、バックトラッキングが多く発生する可能性があり、パフォーマンスに影響を与えることがあります
- 可能な場合は、より具体的なパターンを使用することを検討してください
# 非効率な非貪欲マッチング
text = "a" * 1000 + "b"
pattern = r"a*?b"
# マッチするまでに多数のバックトラッキングが発生
# より効率的な代替パターン
pattern = r"[^b]*b"
# 否定文字クラスを使用することで、バックトラッキングを削減- 適切なパターン選択
- 必ずしも非貪欲マッチングが最適解とは限りません
- 文脈に応じて、否定文字クラス
[^...]や、より具体的な文字クラスの使用を検討してください
# HTMLタグの抽出の別アプローチ
text = "<p>段落1</p><p>段落2</p>"
# 非貪欲マッチングを使用
pattern1 = r'<p>.*?</p>'
# より具体的なパターンを使用
pattern2 = r'<p>[^<]*</p>'
# どちらも同じ結果を得られますが、
# pattern2の方がより効率的で意図が明確ですこれらの例で示したように、貪欲マッチングと非貪欲マッチングの適切な使い分けは、正規表現を効果的に活用する上で重要なスキルとなります。特にHTMLやXMLのパース、引用文の抽出など、実際のテキスト処理では頻繁に使用される技術です。
まとめ
Pythonの正規表現は強力な文字列処理ツールですが、適切に使用することが重要です:
- 基本的なパターンマッチングから始める
- 必要に応じてグループを使用する
- パフォーマンスを考慮してパターンをコンパイルする
- 適切なエスケープとフラグを使用する
- 貪欲/非貪欲マッチングの違いを理解する
参考リンク
- Python公式ドキュメント – reモジュール
- Python Regular Expressions – Google for Education
- RegexOne – 対話式正規表現学習サイト
- Regex101 – オンライン正規表現テスター
最後に、書籍のPRです。
24年9月に出版された「ハイパーモダンPython-信頼性の高いワークフローを構築するモダンテクニック」、Claudio Jolowicz著、嶋田、鈴木訳。開発環境の構築、プロジェクトの管理、テストに関して実践的な内容でとても参考になる一冊です。ぜひ手に取ってみてください。
最後まで読んでいただきありがとうございます。


コメント