Edited at

Pythonでの正規表現の使い方

More than 5 years have passed since last update.

正規表現の検索演算子やパターンや検索自体のルールはPerlやPHPとほとんど変わりないみたいですが。

正規表現の関数の使い方などは全然違うので、自分の勉強&整理の為に書いておきます。


正規表現の検索演算子などには言及しません


初期設定

以下のライブラリーを読み込むことで、正規表現が使えるようになります。


読み込み

import re


正規表現を使うためには、2つ方法があります。

一つは、事前に検索するパターンをコンパイルしておく方法です。

この方法を使うと、同じパターンで何度も検索する場合に、毎回パターンを指定する必要なく、高速に検索することが出来るようになります。

http://docs.python.jp/3/howto/regex.html#compiling-regular-expressions

それから、パターンの最初にrを付けることをを勧めします、付けなくても基本的には大丈夫ですが、付けることによって文字列中のバックスラッシュ文字をそのままバックスラッシュとして扱えるので、パターンの書き方が分かりやすくなります。

http://docs.python.jp/3/howto/regex.html#the-backslash-plague


compile

pattern = r"ca"

text = "caabsacasca"
repatter = re.compile(pattern)
matchOB = repatter.match(text)


もう一つはコンパイルせず、検索時にパターンを設定する方法です。

この場合、検索パターンを使いまわすことがない場合はこちらを使うとよいでしょう。


NoCompile

pattern = r"ca"

text = "caabsacasca"
matchOB = re.match(pattern , text)


検索方法

検索の方法は大きく分けて4つあります。

http://docs.python.jp/3/howto/regex.html#performing-matches

メソッド/属性
目的

match(pattern, string)
文字列の先頭で正規表現とマッチするか判定します。

search(pattern, string)
文字列を操作して、正規表現がどこにマッチするか調べます。

findall(pattern, string)
正規表現にマッチする部分文字列を全て探しだしリストとして返します。

finditer(pattern, string)
正規表現にマッチする部分文字列を全て探しだし iterator として返します。


その他関数(参考)

http://docs.python.jp/2.7/library/re.html#re.split

メソッド/属性
目的

split(pattern, string)
正規表現にマッチする部分があるたびに分割します。

sub(pattern, repl, string)
正規表現にマッチする部分をreplにある文字に置き換えます

検索の方法を1つずつ見て行きます。


match()関数

これは、文字列の先頭でパターンがマッチするかどうかを判定する関数です。

にはmatchObjectオブジェクトがmatchOBに入る。このオブジェクトから、マッチした部分を取り出す(str)には.group()関数を使います(group()関数以外にもオブジェクトから情報を取り出す関数があるので後述します)


match

pattern = r"ca"

text = "caabsacasca"
matchOB = re.match(pattern , text)
if matchOB:
print matchOB.group() # 'ca'


オブジェクトから情報を取り出す関数

メソッド/属性
目的

group()
正規表現にマッチした文字列を返す。

start()
マッチの開始位置を返す。

end()
マッチの終了位置を返す。

span()
マッチの位置 (start, end) を含むタプルを返す。


search()関数

文字列の中にパターンとマッチする部分があるかどうかを判定する関数。match()関数と違い、パターンが文字列の先頭になくてもマッチしてくれる。ただし、マッチする箇所が複数ある場合でも、最初の箇所しか返しません。


search


pattern = r"ca"
text = "caabsacasca"
matchOB = re.search(pattern , text)

if matchOB:
print matchOB
print matchOB.group() # マッチした文字列を返す # ca
print matchOB.start() # マッチの開始位置を返す # 0
print matchOB.end() # マッチの終了位置を返す # 2
print matchOB.span() # マッチの位置(start, end)を含むタプルを返す # (0, 2)



findall()関数

文字列の中のパターンとマッチする部分をすべてリストとして返す関数。search()と違って、マッチする箇所をすべて取得可能。

ただし、戻り値はmatchObjectではなく、ただの文字列のリスト(list)になるので、group()などは利用できません。


findall

pattern = r"ca"

text = "caabsacasca"
# パターンにマッチしたすべてをリストとして返す
matchedList = re.findall(pattern,text)
if matchedList:
print matchedList # ['34567', '34567']


finditer()関数

文字列の中のパターンとマッチする部分をイテレータで返す関数。戻り値をforループなどを回すことによって、findall()関数と同じで、マッチする箇所をすべて取得可能です、findall()関数はリストを返すが、finditer()関数はループ内でオブジェクトを返すので、end(),start()などが利用できます。


finditer

pattern = r"ca"

text = "caabsacasca"
# パターンにマッチしたすべてをイテレータとして返す
iterator = re.finditer(pattern ,text)
for match in iterator:
print match.group() # 1回目: ca 2回目: ca
print match.start() # 1回目: 0 2回目: 6
print match.end() # 1回目: 2 2回目: 8
print match.span() # 1回目: (0, 2) 2回目: (6, 8)



プロパティ

perlなどの正規表現ではパターンの末尾に/pattern/s(.が改行にマッチする)や/pattern/i(大文字小文字を区別)などのプロパティを設定することができるが、Pythonでは以下のようにします。


match

pattern = r"avSCSA"

text = "AVscsa"
------------------------
#コンパイルするパターン

repatter = re.compile(pattern, re.IGNORECASE)#大文字小文字の区別をしない
matchOB = repatter.match(text)

------------------------
#コンパイルしないパターン
matchOB = re.match(pattern , text, re.IGNORECASE)#大文字小文字の区別をしない
--------------------------
if matchOB:
print match.group() # ''


以下のプロパティは必ず前にre.をつけて使用してください。re. DOTALL re.L のように。

プロパティ
意味

ASCII, A
\w, \b, \s, そして \d などをそれぞれのプロパティをもつ ASCII 文字だけにマッチさせます。

DOTALL, S
. を改行を含む任意の文字にマッチするようにします

IGNORECASE, I
大文字小文字を区別しないマッチを行います

LOCALE, L
ロケールに対応したマッチを行います

MULTILINE, M
^ や $ に作用して、複数行にマッチング

VERBOSE, X (for ‘extended’)
冗長な正規表現を利用できるようにして、よりきれいで理解しやすくまとめることができます。


日本語の扱い方

最後に、日本人pythonistaをいつも惑わす日本語の取り扱い方の説明です。

普通の文字列(str)型でも大丈夫な場合もあるようですが



matchOB = re.match("あ","あ")

print matchOB.group()
#あ

以下のようにすると?になってしまうようです


[ぁ-ゞ]

matchOB = re.match("[ぁ-ゞ]","ば")

#?

unicodeにすれば大丈夫


u[ぁ-ゞ]

matchOB = re.match(u"[ぁ-ゞ]",u"ば")

#ば

ということなので、日本語を取り扱うときは一旦Unicode型にしてからにしましょう


参考


str→unicode

u = "日本語".decode("utf-8")

print type(u)
#unicode
print u
#日本語



unicode→str

u = u"日本語".encode("utf-8")

print type(u)
#unicode
print u
#日本語



疑問

それから、unicodeを扱うときはオプションとしてre.Uをつけろと書いてあるが、付けても付けなくても一緒の解答になる気がするんですが、誰か教えて下さい〜

http://pepper.is.sci.toho-u.ac.jp/index.php?%A5%CE%A1%BC%A5%C8%2FPython%2F%B4%C1%BB%FA%A4%CE%C0%B5%B5%AC%C9%BD%B8%BD


re.U

s = u'今日は良い天気《です》ね'

r = re.compile(u'《[^》]*》')
news = r.sub('*', s, re.U)
print s, '>', news
#今日は良い天気《です》ね > 今日は良い天気*ね


not(re.U)

s = u'今日は良い天気《です》ね'

r = re.compile(u'《[^》]*》')
news = r.sub('*', s)
print s, '>', news
#今日は良い天気《です》ね > 今日は良い天気*ね


参考

参考にさせていただいたページです


正規表現 HOWTO — Python 3.4.1 ドキュメント - http://docs.python.jp/3/howto/regex.html

Pythonでの正規表現の簡単なまとめ - minus9d's diary - http://minus9d.hatenablog.com/entry/20120713/1342188160

7.2. re — 正規表現操作 — Python 2.7ja1 documentation - http://docs.python.jp/2.7/library/re.html

Pythonの正規表現モジュールにおける日本語の扱いについて - 試験運用中なLinux備忘録 - http://d.hatena.ne.jp/kakurasan/20090424/p1

pythonの正規表現で日本語を扱う | taichino.com - http://taichino.com/programming/1272