[Python] 正規表現でパターンに合う文字列を抽出する方法

Pythonで正規表現を使用してパターンに合う文字列を抽出するには、標準ライブラリのreモジュールを使用します。

主にre.findall()re.search()re.match()が使われます。

re.findall()は、パターンに一致するすべての部分文字列をリストで返し、re.search()は最初に一致した部分文字列を返します。

re.match()は文字列の先頭から一致するかを確認します。

正規表現パターンはr'パターン'の形式で指定します。

この記事でわかること
  • Pythonの正規表現の基本的な使い方
  • メタ文字や特殊シーケンスの活用法
  • 高度な正規表現のテクニック
  • 文字列抽出の具体的な実例
  • 正規表現のオプション設定の方法

目次から探す

Pythonで正規表現を使う方法

Pythonで正規表現を扱うためには、標準ライブラリのreモジュールを使用します。

このモジュールを使うことで、文字列のパターンマッチングや抽出、置換などが簡単に行えます。

reモジュールのインポート

まず、正規表現を使用するためにreモジュールをインポートします。

import re

re.findall()でパターンに一致する文字列を抽出

re.findall()関数は、指定したパターンに一致するすべての文字列をリストとして返します。

import re
text = "私のメールアドレスは example@example.com です。"
pattern = r'\w+@\w+\.\w+'
result = re.findall(pattern, text)
print(result)
['example@example.com']

この例では、メールアドレスの形式に一致する部分を抽出しています。

re.search()で最初に一致する文字列を抽出

re.search()関数は、指定したパターンに最初に一致する部分を見つけ、その情報を持つマッチオブジェクトを返します。

import re
text = "私の電話番号は 090-1234-5678 です。"
pattern = r'\d{3}-\d{4}-\d{4}'
match = re.search(pattern, text)
if match:
    print(match.group())
090-1234-5678

この例では、電話番号の形式に一致する最初の部分を抽出しています。

re.match()で文字列の先頭から一致を確認

re.match()関数は、文字列の先頭からパターンに一致するかどうかを確認します。

import re
text = "Pythonは楽しいプログラミング言語です。"
pattern = r'Python'
match = re.match(pattern, text)
if match:
    print("一致しました:", match.group())
else:
    print("一致しませんでした。")
一致しました: Python

この例では、文字列の先頭が Python で始まるかどうかを確認しています。

re.finditer()で一致する部分をイテレータで取得

re.finditer()関数は、指定したパターンに一致する部分をイテレータとして返します。

これにより、マッチオブジェクトを逐次処理できます。

import re
text = "abc123def456ghi789"
pattern = r'\d+'
matches = re.finditer(pattern, text)
for match in matches:
    print(match.group())
123
456
789

この例では、数字の部分をすべて抽出しています。

re.sub()でパターンに一致する部分を置換

re.sub()関数は、指定したパターンに一致する部分を別の文字列に置換します。

import re
text = "私の電話番号は 090-1234-5678 です。"
pattern = r'\d{3}-\d{4}-\d{4}'
replacement = "XXX-XXXX-XXXX"
result = re.sub(pattern, replacement, text)
print(result)
私の電話番号は XXX-XXXX-XXXX です。

この例では、電話番号を XXX-XXXX-XXXX に置換しています。

正規表現の基本的なパターン

正規表現では、特定のパターンに基づいて文字列を検索・抽出するためのさまざまなメタ文字や特殊シーケンスが用意されています。

これらを理解することで、より複雑なパターンマッチングが可能になります。

メタ文字の使い方

メタ文字は、正規表現の中で特別な意味を持つ文字です。

以下に代表的なメタ文字を紹介します。

. (任意の1文字)

.は任意の1文字にマッチします。

改行文字以外のすべての文字に一致します。

import re
text = "abc, a1c, a-c"
pattern = r'a.c'
result = re.findall(pattern, text)
print(result)
['abc', 'a1c', 'a-c']

^ (行頭)

^は文字列の先頭にマッチします。

行の最初に特定の文字列があるかどうかを確認するのに使います。

import re
text = "Pythonは楽しい\nJavaも楽しい"
pattern = r'^Python'
match = re.search(pattern, text, re.MULTILINE)
if match:
    print("一致しました:", match.group())
一致しました: Python

$ (行末)

$は文字列の末尾にマッチします。

行の最後に特定の文字列があるかどうかを確認するのに使います。

import re
text = "Pythonは楽しい\nJavaも楽しい"
pattern = r'楽しい$'
match = re.search(pattern, text, re.MULTILINE)
if match:
    print("一致しました:", match.group())
一致しました: 楽しい

[] (文字クラス)

[]を使うことで、指定した文字のいずれか1文字にマッチします。

import re
text = "apple, banana, cherry"
pattern = r'[ab]anana'
result = re.findall(pattern, text)
print(result)
['banana']

| (OR条件)

|を使うことで、複数のパターンのいずれかにマッチします。

import re
text = "猫と犬が好きです。"
pattern = r'猫|犬'
result = re.findall(pattern, text)
print(result)
['猫', '犬']

繰り返しを表すメタ文字

繰り返しを表すメタ文字を使うことで、特定のパターンが何回繰り返されるかを指定できます。

* (0回以上の繰り返し)

*は直前の文字が0回以上繰り返されることにマッチします。

import re
text = "aaa, aa, a, "
pattern = r'a*'
result = re.findall(pattern, text)
print(result)
['aaa', 'aa', 'a', '']

+ (1回以上の繰り返し)

+は直前の文字が1回以上繰り返されることにマッチします。

import re
text = "aaa, aa, a, "
pattern = r'a+'
result = re.findall(pattern, text)
print(result)
['aaa', 'aa', 'a']

? (0回または1回の繰り返し)

?は直前の文字が0回または1回だけ出現することにマッチします。

import re
text = "abc, ac, a"
pattern = r'a?c'
result = re.findall(pattern, text)
print(result)
['ac', 'c', 'c']

{n,m} (n回からm回の繰り返し)

{n,m}は直前の文字がn回からm回繰り返されることにマッチします。

import re
text = "aaa, aa, a, "
pattern = r'a{1,3}'
result = re.findall(pattern, text)
print(result)
['aaa', 'aa', 'a']

特殊シーケンス

特殊シーケンスは、特定の種類の文字にマッチするための短縮表現です。

\d (数字)

\dは任意の数字(0-9)にマッチします。

import re
text = "私の年齢は30歳です。"
pattern = r'\d+'
result = re.findall(pattern, text)
print(result)
['30']

\w (単語文字)

\wは任意の単語文字(アルファベット、数字、アンダースコア)にマッチします。

import re
text = "Python_3.8"
pattern = r'\w+'
result = re.findall(pattern, text)
print(result)
['Python_3', '8']

\s (空白文字)

\sは任意の空白文字(スペース、タブ、改行など)にマッチします。

import re
text = "Hello, World!"
pattern = r'\s+'
result = re.split(pattern, text)
print(result)
['Hello,', 'World!']

\b (単語境界)

\bは単語の境界にマッチします。

これにより、特定の単語が他の文字に囲まれていないかを確認できます。

import re
text = "私はPythonが好きです。"
pattern = r'\bPython\b'
match = re.search(pattern, text)
if match:
    print("一致しました:", match.group())
一致しました: Python

実践例:正規表現で文字列を抽出する

正規表現を使うことで、特定のパターンに一致する文字列を簡単に抽出できます。

ここでは、実際の例を通じて、さまざまな文字列を抽出する方法を紹介します。

メールアドレスを抽出する

メールアドレスの形式に一致する文字列を抽出するための正規表現を使用します。

import re
text = "私のメールは example@example.com と test@test.co.jp です。"
pattern = r'\w+@\w+\.\w+'
result = re.findall(pattern, text)
print(result)
['example@example.com', 'test@test.co.jp']

この例では、メールアドレスの形式に一致する部分をすべて抽出しています。

電話番号を抽出する

日本の電話番号形式(例:090-1234-5678)に一致する文字列を抽出します。

import re
text = "連絡先は 090-1234-5678 と 03-1234-5678 です。"
pattern = r'\d{2,4}-\d{2,4}-\d{4}'
result = re.findall(pattern, text)
print(result)
['090-1234-5678', '03-1234-5678']

この例では、電話番号の形式に一致する部分を抽出しています。

URLを抽出する

ウェブサイトのURLを抽出するための正規表現を使用します。

import re
text = "訪問先は https://www.example.com と http://example.org です。"
pattern = r'https?://[^\s]+'
result = re.findall(pattern, text)
print(result)
['https://www.example.com', 'http://example.org']

この例では、HTTPまたはHTTPSで始まるURLを抽出しています。

日付形式を抽出する

日付の形式(例:YYYY/MM/DDやDD-MM-YYYY)に一致する文字列を抽出します。

import re
text = "重要な日付は 2023/10/01 と 01-10-2023 です。"
pattern = r'\d{4}/\d{1,2}/\d{1,2}|\d{1,2}-\d{1,2}-\d{4}'
result = re.findall(pattern, text)
print(result)
['2023/10/01', '01-10-2023']

この例では、異なる日付形式に一致する部分を抽出しています。

特定の単語やフレーズを抽出する

特定の単語やフレーズを抽出するための正規表現を使用します。

import re
text = "私はPythonとJavaが好きです。Pythonは楽しい言語です。"
pattern = r'Python'
result = re.findall(pattern, text)
print(result)
['Python', 'Python']

この例では、 Python という単語が含まれる部分をすべて抽出しています。

正規表現のオプション

正規表現を使用する際には、さまざまなオプションを指定することで、マッチングの挙動を変更できます。

以下に代表的なオプションを紹介します。

大文字小文字を無視するre.IGNORECASE

re.IGNORECASEオプションを使用すると、大文字と小文字を区別せずにマッチングを行うことができます。

import re
text = "Pythonは楽しい。pythonも楽しい。"
pattern = r'python'
result = re.findall(pattern, text, re.IGNORECASE)
print(result)
['Python', 'python']

この例では、re.IGNORECASEを指定することで、 Pythonpython の両方に一致しています。

複数行に対応するre.MULTILINE

re.MULTILINEオプションを使用すると、文字列内の各行の先頭や末尾に対して^$がマッチするようになります。

import re
text = "Pythonは楽しい\nJavaも楽しい"
pattern = r'^Python'
match = re.search(pattern, text, re.MULTILINE)
if match:
    print("一致しました:", match.group())
一致しました: Python

この例では、re.MULTILINEを指定することで、複数行のテキストの先頭に Python があるかどうかを確認しています。

ドットが改行にも一致するre.DOTALL

re.DOTALLオプションを使用すると、.が改行文字にも一致するようになります。

通常、.は改行文字には一致しませんが、このオプションを指定することで、改行を含む任意の文字にマッチします。

import re
text = "Pythonは楽しい。\nJavaも楽しい。"
pattern = r'Python.*Java'
match = re.search(pattern, text, re.DOTALL)
if match:
    print("一致しました:", match.group())
一致しました: Pythonは楽しい。
Java

この例では、re.MULTILINEを指定することで、改行を含む PythonJava の間のすべての文字に一致しています。

コメントを許可するre.VERBOSE

re.VERBOSEオプションを使用すると、正規表現内にコメントを含めることができ、可読性を向上させることができます。

このオプションを使用すると、空白やコメントが無視されます。

import re
pattern = r"""
    \d{3}  # 3桁の数字
    -      # ハイフン
    \d{4}  # 4桁の数字
    -      # ハイフン
    \d{4}  # 4桁の数字
"""
text = "電話番号は 090-1234-5678 です。"
match = re.search(pattern, text, re.VERBOSE)
if match:
    print("一致しました:", match.group())
一致しました: 090-1234-5678

この例では、re.VERBOSEを指定することで、正規表現にコメントを追加し、各部分の意味を明確にしています。

応用例:正規表現を使った高度な操作

正規表現は、基本的なパターンマッチングだけでなく、より高度な操作にも対応しています。

ここでは、グループ化や先読み、再帰的なパターンマッチングなどの応用例を紹介します。

グループ化とキャプチャ

グループ化を使用すると、特定の部分をまとめて扱うことができ、キャプチャを使ってその部分を抽出することができます。

グループは丸括弧()で囲みます。

import re
text = "私の名前は山田太郎です。"
pattern = r'私の名前は(.*?)です。'
match = re.search(pattern, text)
if match:
    print("キャプチャした名前:", match.group(1))
キャプチャした名前: 山田太郎

この例では、名前の部分をキャプチャして抽出しています。

非キャプチャグループ

非キャプチャグループは、(?:...)の形式で指定し、マッチングには使用しますが、キャプチャは行いません。

これにより、不要なキャプチャを避けることができます。

import re
text = "apple, banana, cherry"
pattern = r'(?:apple|banana)'
result = re.findall(pattern, text)
print(result)
['apple', 'banana']

この例では、(?:...)を使用して、キャプチャせずに apple または banana に一致する部分を抽出しています。

先読み・後読み

先読み(lookahead)と後読み(lookbehind)を使用すると、特定の条件を満たす場合にのみマッチングを行うことができます。

先読み

先読みは、(?=...)の形式で指定し、後ろに特定のパターンが続く場合にマッチします。

import re
text = "Pythonは楽しい。Javaも楽しい。"
pattern = r'Python(?=は)'
match = re.search(pattern, text)
if match:
    print("先読みで一致:", match.group())
先読みで一致: Python

この例では、 Python の後に「は」が続く場合に一致しています。

後読み

後読みは、(?<=...)の形式で指定し、前に特定のパターンがある場合にマッチします。

import re
text = "私の好きな言語はPythonです。"
pattern = r'(?<=好きな言語は)Python'
match = re.search(pattern, text)
if match:
    print("後読みで一致:", match.group())
後読みで一致: Python

この例では、「好きな言語は」の後に Python が続く場合に一致しています。

<...>の部分をグループ化し、対応する閉じタグを確認しています。

よくある質問

re.search()とre.match()の違いは?

re.search()re.match()は、どちらも正規表現を使って文字列を検索するための関数ですが、主な違いはマッチングの位置にあります。

  • re.search(): 文字列全体を対象にして、指定したパターンがどこかに一致するかを探します。

文字列の先頭以外でも一致があれば、その位置を返します。

  • re.match(): 文字列の先頭からのみパターンに一致するかを確認します。

先頭に一致しない場合は、マッチしません。

import re
text = "Pythonは楽しい"
print(re.search(r'楽しい', text))  # 一致する
print(re.match(r'楽しい', text))   # 一致しない

正規表現が遅い場合の対処法は?

正規表現が遅くなる原因はいくつかありますが、以下の対処法を試すことでパフォーマンスを改善できる場合があります。

  1. パターンを簡素化する: 複雑なパターンは処理に時間がかかるため、可能な限りシンプルにします。
  2. キャプチャグループを減らす: 不要なキャプチャグループを使用しないようにし、非キャプチャグループを使うことを検討します。
  3. 先読みや後読みを避ける: これらの機能は計算コストが高くなることがあるため、必要な場合にのみ使用します。
  4. 文字列の長さを制限する: 大きな文字列を処理する場合、必要な部分だけを対象にすることで速度を向上させることができます。
  5. コンパイルを使用する: 正規表現を何度も使用する場合、re.compile()を使ってパターンを事前にコンパイルしておくと、パフォーマンスが向上します。

特殊文字をエスケープする方法は?

正規表現では、特定の文字(例:.*?+(){}[]^$|)は特別な意味を持ちます。

これらの文字を文字通りに扱いたい場合は、エスケープする必要があります。

エスケープするには、バックスラッシュ\を使用します。

例えば、.を文字として扱いたい場合は、\.と記述します。

import re
text = "ファイル名はexample.txtです。"
pattern = r'example\.txt'
match = re.search(pattern, text)
if match:
    print("一致しました:", match.group())
一致しました: example.txt

この例では、.をエスケープすることで、ファイル名の一部として正しくマッチさせています。

まとめ

この記事では、Pythonにおける正規表現の基本的な使い方から、応用的なテクニックまで幅広く解説しました。

正規表現を活用することで、文字列のパターンマッチングや抽出、置換が効率的に行えるようになります。

これを機に、実際のプログラミングに正規表現を取り入れて、より複雑な文字列処理に挑戦してみてください。

  • URLをコピーしました!
目次から探す