正規表現によるパターンマッチング

 

Pythonで動かして学ぶ 自然言語処理入門

中古価格
¥2,999から
(2019/6/4 11:57時点)

逆引きPython標準ライブラリ 目的別の基本レシピ180 ! impress top gearシリーズ

正規表現(正則表現)

 正規表現 (regular expression) とは、共通パターンをもつ文字列の集合を記号で表すためのルールです。たとえば、次のような文字列の集合を考えてみます。

 {第1話, 第2話, 第3話, ... 第一話, 第二話, 第三話, ...}

 どの要素にも、先頭に「第」と末尾に「話」という文字があって、真ん中の文字だけが異なっています。そこで真ん中の文字だけを "." で代用して「第.話」と表すことに決めます。

 "." には数字が入るとは限らないので、正規表現「第.話」の集合は「第猫話」とか「第↑話」というような意味のない文字列も含むことになりますが、とにかく「第.話」で検索をかけると、文書中から「第1話」や「第八話」などの文字列を見つけ出すことができます。

 このとき、"." のような記号を「普通の文字より上の階層にある文字」という意味で、メタ文字 (meta-character) とよびます。メタというのは「高次の」とか「超」を意味するギリシア語由来の接頭辞です。
 
 標準ライブラリの re モジュールをインポートすると、Python で正規表現を使うことができるようになります。以下では、パターンマッチの基本操作について解説します。
 

パターンマッチング

 検査対象文字列の中に、正規表現で記述したパターンと適合する文字列があるかを調べることをパターンマッチングといいます。reモジュールを用いるパターンマッチングには、大まかに分けて関数型とオブジェクト指向の 2 種類の方法があります。当サイトでは詳細な検索設定が可能なオブジェクト指向を採用します。

 オブジェクト指向のパターンマッチングでは、最初に正規表現を re.compile() に渡して正規表現オブジェクト (regexオブジェクト) を作成します。

 re.compile(正規表現のパターン [,フラグ])

 正規表現オブジェクトのメソッドを呼び出すことによって、様々な検索処理を実行できます。

 メタ文字を使わない簡単なパターンマッチの例を見てみましょう。'Python' という文字列を探す正規表現オブジェクトと、検査対象文字列を作成して、regex.findall() を使ってパターンに一致した文字列のリストを取得してみます。

# reモジュールをインポート
import re

# 正規表現オブジェクトを作成
regex = re.compile(r'Python')

# 検査対象文字列を作成
line = '今日もPython、明日もpython'

# lineの中から'Python'を検索
f = regex.findall(line)

print(f)
['Python']

 今の場合、'Python' という文字列が正規表現です。引数には raw 文字であることを示す r を添えて、r'Python' を渡しています。

 このように、メタ文字を含まない単純な文字列が正規表現として渡された場合、特に何も指定しなければ、検査対象から 'Python' に厳密に一致する文字列だけを探します。

 上のコードの検査対象には 'python' という文字が含まれていますが、先頭が小文字になっているので検索にかかりません。大文字と小文字を区別しない場合は、正規表現オブジェクトのオプション引数フラグに re.I を渡します。

# reモジュールをインポート
import re

# 正規表現オブジェクト(大文字・小文字の区別なし)を作成
regex2 = re.compile(r'Python', re.I)

# 検査対象文字列を作成
line = '今日もPython、明日もpython'

# lineの中から'Python'を検索
f = regex2.findall(line)

print(f)
['Python', 'python']

 今度は 'python' という文字列も「パターンマッチした」と判定されています。

 regex.search()メソッドを使うと、パターンマッチした文字列と、その位置情報 (match オブジェクト) を取得することができます。また、match オブジェクトの group()メソッドで、パターンマッチした文字列を取り出すことができます。

# reモジュールをインポート
import re

# 正規表現オブジェクトを作成
regex = re.compile(r'Python')

# 検査対象文字列を作成
line = '今日もPython、明日もpython'

# matchオブジェクトを取得
s = regex.search(line)

print(s)
print(s.group())
<_sre.SRE_Match object; span=(3, 9), match='Python'>
Python

 実行結果を見ると、文字列のインデックス 3 (4 文字目) からインデックス 9 (10 文字目) にかけて、'Python' という文字列が存在していることを知らせています。