【Pythonの正規表現徹底解説】簡単なマッチングから応用例まで

初心者のためのPython正規表現解説
  • URLをコピーしました!

当ブログのコンテンツ・情報について、できる限り正確な情報を提供するように努めておりますが、正確性や安全性を保証するものではありません。
当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますので、予めご了承ください。

この記事では、Pythonにおける正規表現の基本から応用までを解説します。正規表現は、文字列のパターンを検索、マッチング、置換するための強力なツールです。

Pythonの標準ライブラリである"re"モジュールを使用し、Windows 11環境で簡単な例から複雑な例まで順を追って説明します。初心者の方でも理解しやすいように、具体的なコード例を交えて解説します。

目次

この記事で使用するPythonライブラリ

この記事では以下のPythonライブラリを使用します。

ライブラリ用途ライセンス
re正規表現による文字列の操作Python標準モジュール

正規表現とは?

正規表現とは文字列の検索や置換を行うための特殊な文字列パターンです。正規表現を用いることで、特定の文字列パターンを効率的に見つけたり、操作したりすることができます。Pythonでは"re"モジュールを使用して正規表現を扱います。

基本的な使い方

まずは、正規表現の基本的な使い方について解説します。以下は単純な文字列マッチングの例です。

このコードでは、文字列 'abc' が 'abc123' に含まれているかをチェックしています。re.search() 関数を使用してパターンに一致する部分を検索し、結果を表示しています。

import re  # 正規表現モジュールをインポート

# 正規表現パターン
pattern = r'abc'
# マッチング対象の文字列
text = 'abc123'

# マッチングを行う
match = re.search(pattern, text)

if match:
    print("マッチしました!")
else:
    print("マッチしませんでした")

メタ文字

正規表現には特殊な意味を持つ記号(メタ文字)がいくつか存在します。これらを使うことで、より複雑なパターンを表現できます。メタ文字には次のようなものがあります。\はフォントによって見た目が変わります(\)。

メタ文字読み方正規表現としての意味
.ドット任意の1文字(改行を除く)にマッチ
^キャレット、ハット行の先頭にマッチ
$ドル記号行の末尾にマッチ
*アスタリスク0回以上の繰り返しにマッチ
+プラス1回以上の繰り返しにマッチ
?クエスチョンマーク、疑問符0回または1回にマッチ
|パイプOR演算子
[]ブラケット、角括弧文字クラスの定義(例: [a-z])
()パーレン、丸括弧グループ化とキャプチャ
\バックスラッシュ、円記号エスケープ文字

. : 任意の1文字(改行を除く)にマッチ

ドット.は任意の1文字にマッチします。したがってこのコードでは、文字列catの全ての文字がマッチします。

import re

pattern = r'.'
text = 'cat'

matches = re.findall(pattern, text)

print("マッチした文字:", matches)  # 出力: ['c', 'a', 't']

^ : 行の先頭にマッチ

このコードではハット^が行の先頭にあるTheという文字列にマッチします。

import re

pattern = r'^The'
text = 'The quick brown fox'

match = re.search(pattern, text)

if match:
    print("行の先頭にマッチしました!")  # 出力: 行の先頭にマッチしました!

$ : 行の末尾にマッチ

このコードではドル記号$が行の末尾にあるfoxという文字列にマッチします。

import re

pattern = r'fox$'
text = 'The quick brown fox'

match = re.search(pattern, text)

if match:
    print("行の末尾にマッチしました!")  # 出力: 行の末尾にマッチしました!

* : 0回以上の繰り返しにマッチ

このコードではアスタリスク*aの0回以上の繰り返しにマッチします。したがってct,cat,caatの全てがマッチします。

import re

pattern = r'ca*t'
text = 'ct cat caat'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['ct', 'cat', 'caat']

+ : 1回以上の繰り返しにマッチ

このコードではプラス+aの1回以上の繰り返しにマッチします。したがってcatcaatがマッチしますが、ctはマッチしません。

import re

pattern = r'ca+t'
text = 'ct cat caat'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['cat', 'caat']

? : 0回または1回にマッチ

このコードではクエスチョンマーク?uが0回または1回にマッチします。したがってcolorcolourがマッチしますが、colouurはマッチしません。

import re

pattern = r'colou?r'
text = 'color colour colouur'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['color', 'colour']

| : OR演算子

このコードではパイプ|catまたはdogにマッチします。両方の単語が見つかり、結果としてリストに格納されます。

import re

pattern = r'cat|dog'
text = 'I have a cat and a dog.'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['cat', 'dog']

[] : 文字クラスの定義

このコードではブラケット[]を使用して母音 (a,e,i,o,u) にマッチさせています。結果としてpythonの中のoがマッチします。

import re

pattern = r'[aeiou]'
text = 'python'

matches = re.findall(pattern, text)

print("マッチした文字:", matches)  # 出力: ['o']

() : グループ化とキャプチャ

このコードではパーレン()を使用してhelloworldを別々のグループとしてキャプチャしています。match.group() を使用して、各グループの内容を取得できます。

import re

pattern = r'(hello) (world)'
text = 'hello world'

match = re.search(pattern, text)

if match:
    print("グループ1:", match.group(1))  # 出力: グループ1: hello
    print("グループ2:", match.group(2))  # 出力: グループ2: world

\ : エスケープ文字

バックスラッシュ\(円記号\)は正規表現で使用する特殊文字をそのままの文字として扱うことができるようになります。エスケープが必要な特殊文字は下記のとおりです。

.^$*+?{}[]()|\

このコードでは\使用してドル記号$をエスケープしています。これにより、特別な意味を持つメタ文字などをそのままの文字として扱うことができます。

import re

pattern = r'\$100'
text = 'The price is $100.'

match = re.search(pattern, text)

if match:
    print("ドル記号にマッチしました!")  # 出力: ドル記号にマッチしました!

量指定子

量指定子は特定のパターンがどれくらいの回数出現するかを指定するために使用されます。メタ文字で解説した*+?も量指定子の一種です。さらに、特定の回数に制限を設けたい場合には、ブレイス(カーリーブラケット、波括弧){}を使います。

量指定子正規表現としての意味
{n}ちょうどn回
{n,}n回以上
{,m}m回以下
{n,m}n回以上m回以下

{n} : ちょうどn回

{n}はちょうど n 回繰り返されるパターンにマッチします。このコードではパターンa{3}aがちょうど3回連続している部分にマッチし、結果としてaaaがマッチします。

import re

pattern = r'a{3}'
text = 'aa aaaa aaaaa'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['aaa', 'aaa']

{n,} : n回以上

{n,}は少なくとも n 回繰り返されるパターンにマッチします。このコードではパターン a{2,}aが2回以上連続している部分にマッチし、aa, aaa, aaaaが結果としてマッチします。

import re

pattern = r'a{2,}'
text = 'a aa aaa aaaa'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['aa', 'aaa', 'aaaa']

{,m} : m回以下

{,m}はm回以下の繰り返しにマッチします。このコードではパターンa{,2}aが0回以上2回以下連続している部分にマッチし、a,aa,aaが結果としてマッチします。

import re

pattern = r'a{,2}'
text = 'a aa aaa aaaa'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['a', 'aa', 'aa']

{n,m} : n回以上m回以下

{n,m}はn回以上m回以下の繰り返しにマッチします。このコードではパターンa{1,3}aが1回以上3回以下連続している部分にマッチしa,aa,aaa,aaaが結果としてマッチします。

import re

pattern = r'a{1,3}'
text = 'a aa aaa aaaa'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['a', 'aa', 'aaa', 'aaa']

特殊シーケンス

特殊シーケンスは、通常の文字やメタ文字と異なり特定の種類の文字や条件を表すために用いられる正規表現の一部です。

特殊シーケンス正規表現としての意味
\d数字にマッチ([0-9]と同等)
\D数字以外にマッチ([^0-9]と同等)
\S空白文字にマッチ(スペース、タブ、改行など)
\w単語文字にマッチ(アルファベット、数字、アンダースコア)
\W単語文字以外にマッチ
\b単語の境界
\B単語の境界以外
\A文字列の先頭
\Z文字列の末尾
\n改行
\tタブ
\r復帰(キャリッジリターン)
\fフォームフィード
\v垂直タブ

\d : 数字にマッチ

\dは数字にマッチします。文字列Order number: 1234から数字のみが抽出されます。

import re

pattern = r'\d'
text = 'Order number: 1234'

matches = re.findall(pattern, text)

print("マッチした数字:", matches)  # 出力: ['1', '2', '3', '4']

\D : 数字以外にマッチ

\Dは数字以外の文字にマッチします。数字以外の部分が抽出されます。

import re

pattern = r'\D'
text = '123 Main Street'

matches = re.findall(pattern, text)

print("マッチした非数字:", matches)  # 出力: [' ', 'M', 'a', 'i', 'n', ' ', 'S', 't', 'r', 'e', 'e', 't']

\S : 空白文字以外にマッチ

\Sは空白文字以外の文字にマッチします。文字列Hello World!から空白を除いた部分が抽出されます。

import re

pattern = r'\S'
text = 'Hello World!'

matches = re.findall(pattern, text)

print("マッチした非空白文字:", matches)  # 出力: ['H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd', '!']

\w : 単語文字にマッチ

\wは英数字およびアンダースコア"_"にマッチします。文字列Python 3.8から空白とピリオドを除いた部分が抽出されます。

import re

pattern = r'\w'
text = 'Python 3.8'

matches = re.findall(pattern, text)

print("マッチした単語文字:", matches)  # 出力: ['P', 'y', 't', 'h', 'o', 'n', '3', '8']

\W : 単語文字以外にマッチ

\Wは単語文字(英数字およびアンダースコア)以外にマッチします。空白、ピリオド、感嘆符が抽出されます。

import re

pattern = r'\W'
text = 'Python 3.8!'

matches = re.findall(pattern, text)

print("マッチした非単語文字:", matches)  # 出力: [' ', '.','!']

\b : 単語の境界

\bは単語の境界を示し、単語catのみがマッチします。catalogはマッチしません。

import re

pattern = r'\bcat\b'
text = 'The cat sat on the catalog.'

matches = re.findall(pattern, text)

print("マッチした単語:", matches)  # 出力: ['cat']

\B : 単語の境界以外

\Bは単語の境界以外の位置を示し、foobar内の 'foo' がマッチします。fooの後ろに単語の境界がない場合にマッチします。

import re

pattern = r'foo\B'
text = 'foo foobar'

matches = re.findall(pattern, text)

print("マッチした文字列:", matches)  # 出力: ['foo']

\A : 文字列の先頭

\Aは文字列の先頭にマッチします。文字列Python is fun.Pythonがマッチします。

import re

pattern = r'\APython'
text = 'Python is fun.'

match = re.search(pattern, text)

if match:
    print("文字列の先頭にマッチしました!")  # 出力: 文字列の先頭にマッチしました!

\Z : 文字列の末尾

\Zは文字列の末尾にマッチします。文字列Python is funfunがマッチします。

import re

pattern = r'fun\Z'
text = 'Python is fun'

match = re.search(pattern, text)

if match:
    print("文字列の末尾にマッチしました!")  # 出力: 文字列の末尾にマッチしました!

\n : 改行

\nは改行にマッチします。文字列Hello\nWorld全体がマッチします。

import re

pattern = r'Hello\nWorld'
text = 'Hello\nWorld'

match = re.search(pattern, text)

if match:
    print("改行を含む文字列にマッチしました!")  # 出力: 改行を含む文字列にマッチしました!

\t : タブ

\tはタブ文字にマッチします。文字列Hello\tWorldのタブ部分がマッチします。

import re

pattern = r'\t'
text = 'Hello\tWorld'

match = re.search(pattern, text)

if match:
    print("タブにマッチしました!")  # 出力: タブにマッチしました!

\r : 復帰(キャリッジリターン)

キャリッジリターンはテキストのカーソルを行の先頭に移動させる制御文字です。通常、テキストを改行するためには、キャリッジリターンとラインフィードを組み合わせます(\n)が、環境によってはキャリッジリターンだけが使われる場合もあります。

このコードでは\rはキャリッジリターン(復帰)にマッチします。文字列Hello\rWorldのキャリッジリターン部分がマッチします。

import re

pattern = r'\r'
text = 'Hello\rWorld'

match = re.search(pattern, text)

if match:
    print("キャリッジリターンにマッチしました!")  # 出力: キャリッジリターンにマッチしました!

\f : フォームフィード

フォームフィードはプリンターやテキストエディタで新しいページに進むための制御文字です。テキストエディタでは、フォームフィードがページ分割を示すことがあります。

このコードでは\fはフォームフィードにマッチします。文字列Hello\fWorldのフォームフィード部分がマッチします。

import re

pattern = r'\f'
text = 'Hello\fWorld'

match = re.search(pattern, text)

if match:
    print("フォームフィードにマッチしました!")  # 出力: フォームフィードにマッチしました!

\v : 垂直タブ

垂直タブはテキストの垂直方向にタブを挿入するための制御文字です。垂直タブは一般的に使われることはありませんが、特定のテキストレイアウトやデータフォーマットにおいて使用されることがあります。

このコードでは\vは垂直タブにマッチします。文字列Hello\vWorldの垂直タブ部分がマッチします。

import re

pattern = r'\v'
text = 'Hello\vWorld'

match = re.search(pattern, text)

if match:
    print("垂直タブにマッチしました!")  # 出力: 垂直タブにマッチしました!

正規表現の応用例

ここでは、さらに複雑な正規表現を使用した応用例を紹介します。

メールアドレスの抽出

このコードではメールアドレスの形式にマッチするパターンを使って文章中からメールアドレスを抽出しています。re.findall()関数を使用して、全ての一致する部分をリストとして取得しています。

import re

pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
text = 'Contact us at info@example.com for more info.'

matches = re.findall(pattern, text)

print("見つかったメールアドレス:", matches)  # 出力: ['info@example.com']

パターンの置換

このコードでは数字を全てXに置換しています。re.sub()関数を使用して、パターンに一致する部分を指定した文字列で置換します。

import re

pattern = r'\d+'
text = 'The prices are 100, 200, and 300 dollars.'

# 数字を'X'に置換
new_text = re.sub(pattern, 'X', text)

print("置換後のテキスト:", new_text)  # 出力: ['The prices are X, X, and X dollars.']

URLの抽出

このコードではテキストからURLを抽出しています。re.findall()関数を使って、文章中に含まれるすべてのURLを抽出します。

import re

pattern = r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+'
text = 'Check out our website at https://example.com or follow us on https://twitter.com/example.'

urls = re.findall(pattern, text)

print("見つかったURL:", urls)  # 出力: ['https://example.com', 'https://twitter.com/example']

HTMLタグの抽出

このコードではHTMLドキュメントから特定のタグを抽出する方法を示しますre.findall()関数を使って、divタグ内のテキストコンテツを抽出しています。

import re

pattern = r'<div.*?>(.*?)</div>'
html = '<div>Content 1</div><p>Paragraph</p><div>Content 2</div>'

divs = re.findall(pattern, html)

print("見つかったdivタグの内容:", divs)  # 出力: ['Content 1', 'Content 2']

電話番号のフォーマットチェック

このコードではテキスト内の電話番号(一般的なフォーマットとして、(xxx) xxx-xxxxの形式)が特定のフォーマットに一致するかどうかをチェックしています。

import re

pattern = r'\(\d{3}\) \d{3}-\d{4}'
text = 'You can reach us at (123) 456-7890.'

matches = re.findall(pattern, text)

print("見つかった電話番号:", matches)  # 出力: ['(123) 456-7890']

まとめ

正規表現は、文字列操作を効率的に行うための強力なツールです。この記事を通じて、簡単なマッチングから複雑なパターンの処理まで、正規表現の使い方を理解する手助けになれば幸いです。

よかったらシェアしてね!
  • URLをコピーしました!
目次