Python

【Python】正規表現

環境

macOS Big Sur
Python3.8

正規表現

文字列をパターンとして表現する手法を「正規表現」(Regular Expression)といいます。

正規表現では、通常の文字やパターンを表す「メタ文字」・「特殊シーケンス」を組み合わせて文字列を表現します。正規表現で表された文字列を「パターン文字列」といいます。

正規表現において、特定の文字列がパターン文字列と合致することを「マッチする」といいます。

なお、Pythonでは、パターン文字列はraw文字列として定義します。

パターン文字列

以下にメタ文字及び特殊シーケンスを機能別に分類してまとめます(適宜、公式ドキュメントも参照してください)。なお、パターン文字列中でメタ文字と同じ記号を文字として使用したい場合は「\」でエスケープします。

特定の位置でマッチするメタ文字

主な
メタ文字
説明 マッチする文字列
^ 先頭でマッチ。 ^ab abc、abC、abcd等
$ 末尾でマッチ。 ab$ abab、12ab等

特定の文字にマッチするメタ文字

主な
メタ文字
説明 マッチする文字列
. どんな1文字にもマッチ(改行以外)。 a.c abc、aBc等
[] 文字の集合を指定し、そのうちの1文字でマッチ。
集合の前に「^」を入れると集合以外の1文字でマッチ。
①[abc]または[a-c]
②[^abc]
①a、b、cにマッチ。
②a、b、c以外にマッチ。
() 括弧内でグループ化し、グループでマッチ。 (abc) abcde、abc12等

繰り返しにマッチするメタ文字

主な
メタ文字
説明 マッチする文字列
* 直前のパターンを0回以上できるだけ多く繰り返したパターンにマッチ。 ab* a、ab、abb等
+ 直前のパターンを1回以上できるだけ多く繰り返したパターンにマッチ。 ab+ ab、abb、abbb等
? 直前のパターンを0回か1回繰り返したパターンにマッチ。 ab? a、ab
*?、+?、?? 直前のパターンを(*?は0回以上、+?は1回以上、??は0回か1回)できるだけ少なく繰り返したパターンにマッチ。 <aa>bb<cc>の場合
①<.*>
②<.*?>
①は<aa>bb<cc>にマッチ。(できるだけ多い文字列とマッチ。)
②は<aa>にマッチ。(できるだけ少ない文字列とマッチ。)
{m} 直前のパターンをm回繰り返したパターンにマッチ。 a{3} aaa
{m,n} 直前のパターンをmからn回できるだけ多く繰り返したパターンにマッチ。 a{3,5} aaaaaについて、aaaaaにマッチ。
{m,n}? 直前のパターンをmからn回できるだけ少なく繰り返したパターンにマッチ。 a{3,5}? aaaaaについて、aaaにマッチ。
| 2種類のパターンで挟み、いずれかでマッチ。 a|b a、b

文字の種類とマッチする特殊シーケンス

主な
特殊シーケンス
説明
\d 数字にマッチ。
\D 数字以外にマッチ。
\s 空白文字列にマッチ。
\S 空白文字列以外にマッチ。
\w 英数字(大文字小文字含む)1文字及び「_」にマッチ。
\W 英数字及び「_」を除く文字にマッチ。

reモジュール

Pythonでは、正規表現を利用するために「reモジュール」が用意されています。

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

import re

reモジュールを使った正規表現の利用手順

  1. 正規表現のパターン文字列を定義する。
  2. reモジュールの関数を使用してパターン文字列をコンパイルすることで、正規表現オブジェクトを生成する。
  3. 正規表現オブジェクトのメソッドからマッチする文字列を検索する。

または、

  1. 正規表現のパターン文字列を定義する。
  2. reモジュールの関数に直接パターン文字列を渡して、マッチする文字列を検索する。

正規表現オブジェクトの生成

reモジュールの「compile()関数」を使用することで、「正規表現オブジェクト」を生成することができます。

正規表現オブジェクト生成

re.compile(パターン文字列, フラグ)

※パターン文字列はraw文字列で指定します。

フラグを指定することで、より詳細な検索を指定することができます。

フラグはreモジュールの属性のため、「re.I」のように指定します。また、複数のフラグを指定する場合は「|」を使い、「re.I | re.M」のように指定します。

主なフラグ 説明
I (IGNORECASE) 英字の大文字小文字を区別しない。
M (MULTILINE) 改行を考慮する。行の先頭と末尾を見る。メタ文字の「^」と「$」に影響がある。
S (DOTALL) メタ文字の「.」に改行も含むようにする。
A (ASCII) 特殊シーケンスでASCII文字のみマッチするようにする。
L (LOCALE) 特殊シーケンスでロケール(文化によって異なる単位や表記)に従ってマッチするようにする。

正規表現オブジェクトのメソッドを使用することで、対象とする文字列とマッチした文字列を得ることができます。以下、正規表現オブジェクトを「regex」と表現します。

マッチした文字列の取得

regex.findall(対象文字列, pos, endpos)

※マッチした全ての文字列をリストで取得できます。

※引数posで検索開始位置のインデックス(省略時は「0」)、引数endposで検索終了位置のインデックス(省略時は文字列末尾)を指定することもできます。

マッチした文字列で分割

regex.split(対象文字列, 分割数)

※マッチするたびに文字列を分割します。

※第2引数で整数を指定し、分割数を指定することもできます。省略時は最期まで分割します。

マッチした文字列を置換

regex.sub(置換用文字列, 置換を行う文字列, 置換数)

※置換を行う文字列を検索し、マッチするたびに置換用文字列に置換します。

※第3引数で整数を指定し、置換数を指定することもできます。省略時は全ての文字列を置換します。

import re

url_str = "abcd.com efg.net hijk.com lmnop.com qrs.net tuv.com wxyz.xyz"

pattern = r"[a-z]+\.com"  # この「.」はメタ文字ではなためエスケープします。
regex = re.compile(pattern)

print(regex.findall(url_str))
print(regex.split(url_str))  # 先頭または末尾でマッチする場合、リストの先頭または末尾に空文字の要素が含まれます。
print(regex.sub("match", url_str))


# 実行結果
['abcd.com', 'hijk.com', 'lmnop.com', 'tuv.com']
['', ' efg.net ', ' ', ' qrs.net ', ' wxyz.xyz']
match efg.net match match qrs.net match wxyz.xyz

マッチオブジェクトの生成

正規表現オブジェクトから「マッチオブジェクト」を生成し、マッチオブジェクトのメソッドや変数を使用することで、より詳細な情報を得ることができます。

マッチオブジェクト生成

regex.search(対象文字列, pos, endpos)

regex.match(対象文字列, pos, endpos)

regex.finditer(対象文字列, pos, endpos)

※いずれも対象文字列からマッチを検索し、マッチオブジェクトを返すメソッドですが、searchは文字列の全体から検索、matchは文字列の先頭のみ検索、finditerはマッチする文字列を先頭からイテレータで返します。

※引数posで検索開始位置のインデックス(省略時は「0」)、引数endposで検索終了位置のインデックス(省略時は文字列末尾)を指定することもできます。

マッチオブジェクトのメソッド

主な
メソッド
説明
group() マッチした文字列を返す。引数に1以上の整数を与えると、パターン文字列の()でグループ化した位置を指定できる。複数指定するとグループのタプルが取得できる。
groups() マッチした文字列をグループ毎にタプルで返す。
start() 検索結果の開始位置を対象文字列のインデックスで返す。引数に1以上の整数を与えると、そのグループの開始位置を取得できる。
end() 検索結果の終了位置を対象文字列のインデックスで返す。引数に1以上の整数を与えると、そのグループの終了位置を取得できる。

マッチオブジェクトの変数

主な変数 説明
re 正規表現オブジェクトを取得できる。
string 対象文字列を取得できる。
import re

url_str = "abcd/efgh.com"

pattern = r"([a-z]+)/([a-z]+)\.com"
regex = re.compile(pattern)
m = regex.search(url_str)

print(m.groups())
print(m.group(1))
print(m.re)
print(m.string)


# 実行結果
('abcd', 'efgh')
abcd
re.compile('([a-z]+)/([a-z]+)\\.com')
abcd/efgh.com

 

import re

url_str = "abcd.com efg.net hijk.com lmnop.com qrs.net tuv.com wxyz.xyz"

pattern = r"[a-z]+\.com"
regex = re.compile(pattern)

m = regex.finditer(url_str)
print(next(m))
print(next(m))


# 実行結果
<re.Match object; span=(0, 8), match='abcd.com'>
<re.Match object; span=(17, 25), match='hijk.com'>

reモジュール関数による処理

reモジュールには、パターン文字列を直接引数に設定することで、マッチする文字列を検索できる関数が用意されています。

正規表現オブジェクトで説明した各メソッドと同名の関数が定義されており、「re.関数名()」で呼び出し、第1引数にパターン文字列を指定することで、正規表現オブジェクトを使用した場合と同じ結果を得ることができます。