機械学習でデータを形成する際や、スクレイピングでデータの抽出を行うために用いられるpythonのモジュールとしてreというのがあります。
reモジュールでは、正規表現を用いて柔軟に文字列の抽出や置換を行うことができます!
もちろん正規表現についても解説していきます!
最初はとっかかりにくい概念というか、慣れるまで時間がかかるテクニックではあると思いますが、ゆっくり一緒に学んでいきましょう!
正規表現を用いて抽出した例
まずはどんなことができるのかご覧ください。
詳しい説明は後述しますので、まずは流れだけある程度把握できれば万々歳です。
#モジュールのインポート
import re
# 抽出元のテキスト
txt = 'My phone number is 090-9999-9999, email address is emamamail@abc.jp'
# 電話番号抽出
phone_num = re.search(r'[0-9]{3}-[0-9]{4}-[0-9]{4}', txt).group()
# メールアドレス抽出
email = re.search(r'[a-z]+@[a-z]+\.jp', txt).group()
# 出力
phone_num # '090-9999-9999'
email # 'emamamail@abc.jp'
上記では、元となるテキストから電話番号とメールアドレスを抽出しております。
具体的には、下記の条件に当てはまる文字列をテキストに対して検索しています。
・電話番号
-> 「(任意の数字3桁)- (任意の数字4桁)-(任意の数字4桁)」に当てはまる文字列を検索
・メールアドレス
-> 「(アルファベット複数)@(アルファベット複数).jp」に当てはまる文字列を検索
このように、複数の文字列をあるきまった形式で表すための表現方法を正規表現といいます!
例えば、[0-9]{4}は0~9の数字4桁を表します。
なので、電話番号が異なる表記で書かれていた場合引っかかりません笑
# 抽出元のテキスト(電話番号ハイフンなしver.)
txt = 'My phone number is 09099999999, email address is emamamail@abc.jp'
# 電話番号抽出(引っかからないのでエラーとなる)
phone_num = re.search(r'[0-9]{3}-[0-9]{4}-[0-9]{4}', txt).group()
正規表現の一覧はこちらに詳しく載っておりますので引用させていただきます。
抽出パターンをコンパイルする場合としない場合
正規表現を用いて抽出を行う場合に、正規表現のパターンを変数のように格納し、それを使い回す方が可読性も速度も向上する場合があります。
そのパターンを格納する際にコンパイルという作業をする必要があります。
ではまず比較のためにコンパイルなしの場合を見てみましょう!
コンパイルなし
# 抽出元のテキスト
txt = 'My phone number is 090-9999-9999, email address is emamamail@abc.jp'
# 電話番号抽出
phone_num = re.search(r'[0-9]{3}-[0-9]{4}-[0-9]{4}', txt)
# もし検索に引っかかれば出力
if phone_num:
print(phone_num)
print(phone_num.group())
print(phone_num.span())
# <re.Match object; span=(19, 32), match='090-9999-9999'>
# 090-9999-9999
# (19, 32)
先ほどと同じ流れですね。
re.search([検索したい文字列(正規表現など)], [検索元の文字列])
このように記述することで検索をかけることができます。
search()関数以外にも複数関数があり、後述で詳しく解説いたします。
また9~11行目のように、返り値に.group()や.span()を付けることでそれぞれ引っかかった具体的な文字列とインデックスを取得することができます!
続いてはコンパイルありの場合です。
コンパイルあり
# 抽出元のテキスト
txt = 'My phone number is 090-9999-9999, email address is emamamail@abc.jp'
#コンパイル
pattern = re.compile(r'[0-9]{3}-[0-9]{4}-[0-9]{4}')
# 抽出
phone_num = pattern.search(txt)
# もし検索に引っかかれば出力
if phone_num:
print(phone_num)
print(phone_num.group())
print(phone_num.span())
# <re.Match object; span=(19, 32), match='090-9999-9999'>
# 090-9999-9999
# (19, 32)
5行目にてさきほどは無かったコンパイルという処理があるのがお分かりでしょうか。
また8行目の抽出処理においても、
re.search() -> pattern.search()
searchの引数がtxtのみ
と記述方法も変わっております。
コンパイルする場合のメリットとして、処理が早い・同じ抽出パターンを使いまわせるという点が挙げられます。
なので特に意図がない場合はコンパイルした方が良いのかもしれません。(あくまで個人的に)
さまざまなreメソッド
ここまではsearch()関数の一辺倒で説明してきましたが、ここからはそれ以外のさまざまな関数についてご紹介・説明をしていきます!
また説明の便宜上、コンパイルなしの方法で説明させていただきます。
【match】文字列の先頭が検索パターンに当てはまるか検索
match()では、検索パターンが対象文字列の先頭に当てはまるかどうかを調べます。
# 検索元文字列
txt = 'emamamail@abc.jp is my email address.'
# 検索
result = re.match(r'[a-z]+@[a-z]+\.jp', txt)
# 出力
result.group() # 'emamamail@abc.jp'
この場合、txtの先頭が抽出パターンにひっかかったのでメールアドレスが出力されました。
ただし、先頭に引っかからない場合は出力されません。
# 検索元文字列
txt = 'My email address is emamamail@abc.jp.'
# 検索
result = re.match(r'[a-z]+@[a-z]+\.jp', txt)
# 出力
result.group() # エラー
【search】文字列に検索パターンがあるかどうか検索
search()では、検索パターンが対象文字列のどこかに存在すれば結果を返してくれます。
# 検索元文字列
txt = 'My email address is emamamail@abc.jp.This is for you.'
# 検索
result = re.match(r'[a-z]+@[a-z]+\.jp', txt)
# 出力
result.group() # 'emamamail@abc.jp'
ここで一つ注意点なのですが、search()では文字列の中に検索パターンに当てはまる文字列が複数あった場合、一番最初の文字列しか返ってきません。
1つ検索したら満足してしまうのです。
【findall】検索パターンに当てはまるもの全て抽出
search()では1つの検索結果しか返ってこないのに対して、findall()では検索パターンに当てはまる文字列をリストとして全て返してくれます。
# 検索元文字列
txt = 'emamamail@abc.jp, hey@abc.jp, yeah@abc.jp are mail address.'
# 検索
result = re.findall(r'[a-z]+@[a-z]+\.jp', txt)
# 出力(リストで返ってくる)
result
# ['emamamail@abc.jp', 'hey@abc.jp', 'yeah@abc.jp']
このように、当てはまるものが全てリストとして返ってきます。
【sub】検索パターンに当てはまるものを置換
文字列を置換する際はreplace()などを用いるかと思いますが、re.sub()を用いることでより柔軟に置換を行うことができます!
実際に見てみましょう。
# 検索元文字列
txt = 'emamamail@abc.jp, hey@abc.jp, yeah@abc.jp are mail address.'
# 置換
txt = re.sub(r'[a-z]+@[a-z]+\.jp', 'Hit!!!!!!', txt)
# 出力
txt
# 'Hit!!!!!!, Hit!!!!!!, Hit!!!!!! are mail address.'
検索パターン([a-z]+@[a-z]+.jp)に引っかかるメールアドレスが全て「Hit!!!!!!」に置換されました!
sub()を用いる場合は、matchやsearchなどと少し記述方法が異なるので注意しましょう。
txt = re.sub([置換対象のパターン], [置換後の文字列], [置換を行う文字列])
まとめ
今回はpythonのreモジュールの使い方についてご紹介させていただきました!
正規表現を用いることで、より柔軟・スマートに文字列の検索や置換を行うことができます。
実際、スクレイピングで得たデータは不要なスペースや改行などが含まれてしまっているので、そのようなデータを整えるためにreモジュールは重宝します。
全部完璧に今覚える必要はありません!reモジュールの用途を頭に入れて、「たしかそんなやり方もあったなあ」という状態にしておきましょう!
そのとき用途にあったやり方を調べりゃいいんです。
ご覧いただきありがとうございました!
コメント