今回はpythonで正規表現を扱う方法について説明します。
正規表現とは
文字列のあるパターンを様々なメタ文字を用いて一つの文字列として表現をする手法のことです。例えば、WindowsのOSを一つで表現したい場合を考えます。Windowsには、『Windows7』や『Windows10』、『Windowsvista』などがあります。この文字列をみると以下の法則がわかりそうです。
’Windows’ + 何か
この何かの部分が数字であったり、英字であったりし、また文字数も1文字以上とまちまちです。このときの何かを正規表現では『*』(ワイルドカード)で表すことが出来、結果は以下の文字列で表現できます。
Windows*
このように正規表現では、メタ文字(例ではワイルドカード)を用いて文字列のあるパターンを一つの文字列で表現できます。この手法は、ファイルの検索やファイル名の置換の際に用いられます。情報世界では、こういった手法を用いて効率よく、ファイルの検索等が行われています。
ここでいくつかメタ文字をご紹介します。
. | 任意の一文字 | a.b |
---|---|---|
^ | 文字列の先頭 | ^ab |
$ | 文字列の最後 | ab& |
* | 0回以上の繰り返し | ab* |
+ | 1回以上の繰り返し | ab+ |
? | 0回または1回 | ab? |
{m} | m回の繰り返し | ab{2} |
{m,n} | m~n回の繰り返し | ab{2,4} |
[] | 集合 | [a-z] |
| | 和集合 | a|b |
() | グループ化 | (abc)+ |
また、数値や英字などよく使われる正規表現パターンは予め特殊シーケンスとして用意されています。
\d | 任意の数値 | [0-9] |
---|---|---|
\s | 任意の空白文字 | [\t\n\r\f\v] |
\w | 任意の英数字 | [a-zA-Z0-9] |
\A | 文字列の先頭 | ^ |
\Z | 文字列の最後 | $ |
各文字を大文字にするとそれ以外の文字列の正規表現パターンとなります。(『\D』の場合は、任意の数値以外)
Pythonにおける正規表現の基本
Pythonで正規表現を行うには、まず正規表現のパターンをコンパイルしたオブジェクトを作ります。そのオブジェクトの正規表現パターンと検索または置換する文字列が一致するかを見ます。なお、Pythonで正規表現を扱うには『re』モジュールを使います。
正規表現のパターンオブジェクトをつくる(re.compile(正規表現パターン))
正規表現のパターンオブジェクトを作るには、『re.compile(正規表現パターン)』を使います。
>>> import re
>>> pattern = re.compile("Windows")
正規表現のパターンに条件を加える
compileは、『compile(正規表現パターン,修飾子)』で指定できます。この正規表現パターンには、すべての英字を表す『[a-z]』などが指定できます。さらに、修飾子には、大文字小文字を区別しない『re.I』を指定できます。
正規表現のパターンオブジェクトに対する操作
ここでは、作成した正規表現のパターンオブジェクト(以下、パターンオブジェクトと略します)に対する操作についてご紹介します。
汎用的に検索する(オブジェクト.search(検索したい文字列))
検索したい文字列がパターンオブジェクトと一致するかを調べるには、『オブジェクト.search(検索したい文字列)』を使います。一致する場合は、マッチング結果が表示され。一致しない場合は、「None」が返されます。
一致する場合
>>> import re
>>> pattern = re.compile('Win')
>>> pattern.search('Windows')
<_sre.SRE_Match object at 0x7f3cd0e22920>
一致しない場合
>>> import re
>>> pattern = re.compile('Win')
>>> pattern.search('Apple')
>>>
文字列の先頭が一致するかを検索する(パターンオブジェクト.match(検索したい文字列))
searchと似たような検索として、『パターンオブジェクト.match(検索したい文字列)』があります。これは、searchと違って、検索したい文字列の先頭がパターンオブジェクトと一致する場合のみマッチします。
>>> import re
>>> pattern = re.compile('Win')
>>> pattern.match('This is Win - Win') 一致せず
>>>
>>> pattern.search('This is Win - Win')一致する
<_sre.SRE_Match object at 0x7f3cd0e228b8>
置換する(パターンオブジェクト.sub(置換後の文字列,置換したい文字列))
パターンオブジェクトに一致した文字列を指定した文字列に置換するには、『パターンオブジェクト.sub(置換後の文字列,置換したい文字列)』を使います。
>>> import re
>>> pattern = re.compile('s')
>>> pattern.sub('S','Windows')
'WindowS'
特殊な置換として後方参照があります。これは作成した正規表現パターンを置換で使いまわす際に特殊なシーケンスを利用することです。以下にサンプルをあげます。
>>> import re
>>> pattern = re.compile(r'(\d{3})(\d{4})')
>>> pattern.sub(r'\1-\2','0123456')
'012-3456'
その他の記法での検索・置換
“\”を含むraw string記法や日本語を含むUnicodeでの検索・置換も可能です。
>>> import re
>>> pattern = re.compile(r'\\')
>>> pattern.sub('A','\A\B\C')
'AAABAC'
>>> import re
>>> pattern = re.compile(u'[あ-ん]',re.I)
>>> print(pattern.sub('A',u'あAいIうU'))
AAAIAU
部分一致した文字列を抽出する①(パターンオブジェクト.groups())
文字列内の部分ごとに一致した文字列を抽出するには、『パターンオブジェクト.groups()』を使います。その際は、予め正規表現パターンは『()』を使い、グループの境界を示しておきます。
>>> import re
>>> pattern = re.compile(r'(\d+)\.(\d+)\.(\d+).(\d+)')
>>> res = pattern.search('192.168.0.1')
>>> res.groups()
('192', '168', '0', '1')
部分一致した文字列を抽出する②(re.findall(正規表現パターン,抽出したい文字列))
文字列内の部分ごとに一致した文字列を抽出する方法として他にも『re.findall(正規表現パターン,抽出したい文字列)』があります。
>>> import re
>>> re.findall(r'(\d+)\.(\d+)\.(\d+)\.(\d+)','192.168.0.1')
[('192', '168', '0', '1')]
正規表現で文字を分割する(パターンオブジェクト.split(分割したい文字列))
正規表現で文字を分割するには、『パターンオブジェクト.split(分割したい文字列)』を使います。
>>> import re
>>> pattern = re.compile(',+')
>>> pattern.split('a,b,,d,,,g')
['a', 'b', 'd', 'g']
この例だと「,が1回以上連続して登場する文字列」を区切り文字としています。そのため、「,」も「,,」も「,,,」も区切り文字の対象となります。
まとめ
・Pythonで正規表現を行うには、まず正規表現のパターンをコンパイルしたオブジェクトをつくる
・検索や置換もできる