正規表現を使うと、かなり複雑な条件での文字列検索をおこなうことができる。
Pythonで正規表現(regex)を使う場合、組み込みのreモジュールを使用する。
今回はその使い方をいくつか例を挙げて紹介しよう。
コンテンツ
正規表現を使って文字列を分割する
reモジュールの関数は、パターンによるマッチング、分割、置換と、3つに分かれた機能を持っている。
例として、複数の空白やタブ文字が入った文字列変数txtがあるとしよう。
余分な空白文字などを除外した文字列のみを取り出し、文字列ごとに分割したい場合、以下のようにsplit関数を使う。
import re
txt = "foo bar\t hoge \tfuga"
re.split('\s+', txt)
# ['foo', 'bar', 'hoge', 'fuga']
split関数の第一引数には正規表現のパターン「\s+」を指定している。
「\s」は空白文字(改行文字・タブ)を表し、「+」は直前の1文字の1回以上の繰り返しを表すので、マッチしたパターンが区切り文字となり、結果として単語ごとに分割されたリストを得ることができる。
正規表現を使って指定条件のマッチングをおこなう
マッチした文字列全てをリストとして取得する
分割の例では、マッチした文字列を区切り文字としたが、マッチした文字列自体を取得したい場合、findall関数を使う。
import re
txt = "foo bar\t hoge \tfuga"
re.findall('\s+', txt)
# [' ', '\t ', ' \t']
正規表現パターンをオブジェクトとして定義する
同じ正規表現を、複数の文字列に対して適用する場合、re.compileでパターンをオブジェクトとして定義した方が良い。
処理のパフォーマンスが向上する。
regex = re.compile('\s+')
regex.findall(txt)
# [' ', '\t ', ' \t']
search関数とmatch関数
findall関数はマッチした全ての文字列を取得したが、search関数は最初にマッチした文字列のみを取得する。
また、match関数は更に厳格な関数で、文字列の先頭のみでマッチするかのみを調べる。
それぞれの関数の違いは、実例を見た方が分かりやすいと思うので以下のコードを確認してくれ。
import re
mail_list = """hoge@gmail.com
fuga@gmail.com
foo@gmail.com
bar@yahoo.com
"""
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# 正規表現で大文字・小文字を区別しないようにする
regex = re.compile(pattern, flags=re.IGNORECASE)
### findall関数
regex.findall(mail_list)
# ['hoge@gmail.com', 'fuga@gmail.com', 'foo@gmail.com', 'bar@yahoo.com']
### search関数
m = regex.search(mail_list)
# <re.Match object; span=(0, 14), match='hoge@gmail.com'>
mail_list[m.start():m.end()]
# 'hoge@gmail.com'
### match関数
print(regex.match(mail_list))
# <re.Match object; span=(0, 14), match='hoge@gmail.com'>
# 文字列の先頭が一致しない場合はNoneが返される
mail_list = """@@@hoge@gmail.com
fuga@gmail.com
foo@gmail.com
bar@yahoo.com
"""
print(regex.match(mail_list))
# None
正規表現を使って文字列を置換する
最後に文字列置換の例を見ていこう。
置換の場合はsub関数を使う。
先述のマッチングの例で使ったメールリストをそのまま使って例を見ていこう。
import re
mail_list = """hoge@gmail.com
fuga@gmail.com
foo@gmail.com
bar@yahoo.com
"""
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# 正規表現で大文字・小文字を区別しないようにする
regex = re.compile(pattern, flags=re.IGNORECASE)
print(regex.sub('mail_address', mail_list))
# mail_address
# mail_address
# mail_address
# mail_address
正規表現でメールアドレスを細かく分割する
少し正規表現自体の話にシフトするが、ここではメールアドレスをユーザー名、ドメイン名、トップレベルドメインに分割する例を紹介しておく。
import re
mail_list = """hoge@gmail.com
fuga@gmail.com
foo@gmail.com
bar@yahoo.com
"""
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
# 正規表現で大文字・小文字を区別しないようにする
regex = re.compile(pattern, flags=re.IGNORECASE)
m1 = regex.match('hoge@gmail.com')
m1.groups()
# ('hoge', 'gmail', 'com')
m2 = regex.findall(mail_list)
# [('hoge', 'gmail', 'com'),
# ('fuga', 'gmail', 'com'),
# ('foo', 'gmail', 'com'),
# ('bar', 'yahoo', 'com')]