【ユースケース別】Pythonで正規表現抽出

プログラミング

初めに

こんにちは,今回は正規表現で抽出することが多いであろう事例をユースケース毎にざっくりとまとめてみました.
正確な抽出方法ではなく,理解しやすいように汎化させていますので,そこに関してはご承知おきください.

では,早速進めていきたいと思います.

ユースケース別正規表現

事例1:メールアドレス

基本的に英語・数字・記号の組み合わせ,かつ,@以降でドメインを示すというようなルールがメールアドレスにはあります.
これを標準ライブラリの”re”を用いて,抽出していきます.

コード
import re
text_list = ["メールアドレスはabcd-0123@xyz.comです.",
        "メールアドレス:abcd.0123@xxx.yyy.zz", 
        "メールアドレス:abcd_0123@@xyz.com"]
for text in text_list:
    ans = re.findall(r'([a-zA-Z0-9_\-\.]+@[a-zA-Z\.]+)', text)
    if ans:
        print(ans[0])
    else:
        print("no mail-address")
#出力
abcd-0123@xyz.com
abcd.0123@xxx.yyy.zz
no mail-address
解説

[ ]の中を説明していきます. “a-zA-Z”は小文字と大文字のaからzまでを表しています.
“0-9″は0から9の数字を表しています.
“_\-\.”はアンダーバーとハイフンとピリオドを使えるようにしています.
また,ハイフンとピリオドに関しては正規表現の特殊記号としての用途もあるので記号として扱う場合はバックスラッシュをつける必要があります.
“+”の意味は一回以上の繰り返しを表しています.
よって,「英字+数字+記号(-._)」の一回以上の繰り返し+@+「英字+ピリオド」の一回以上の繰り返しを抽出してくれるのが上記のコードになります.

事例2:電話番号

電話番号は数字の桁の組み合わせですが,ハイフンを使ったり,+81などの国際電話識別番号が使われたりします.
これらを標準ライブラリの”re”を用いて,抽出できるようにします.

コード
import re
#携帯電話の11桁を想定
text_list = ["電話番号:080-0000-0000", "電話番号:08011112222", "電話番号:+818011112222","電話番号:080-abcd-2222"]
for text in text_list:
    ans = re.findall(r'(\+?[0-9]{3}\-[0-9]{4}\-[0-9]{4}|\+?[0-9]{11,12})', text)
    if ans:
        print(ans[0])
    else:
        print("no phone number")
#出力
080-0000-0000
08011112222
+818011112222
no phone number
解説

ハイフン付きの場合[0-9]x3 – [0-9]x4 – [0-9]x4 を抽出します.
“[0-9]{3}\-[0-9]{4}\-[0-9]{4}”が上記を表しています.
(‘条件1|条件2’)とすることで,どちらかの条件を満たす部分を抽出することができます.
後半の条件部分の最初,”\+?”の部分は”+”という記号が0,1回出てくるということを表しています.
ハイフンなしの場合は単純に国際電話番号の場合は12桁分,電話番号の場合11桁分抽出すればいいので{11,12}を指定しています.
また,上記のままだと大量に数字が入力されている場合抽出してしまうので携帯なら最初が080や070,090で固定されているので,そういった条件を追加することで過検出を抑えられると思います.

事例3:日付

日付は,年月日とyyyy/mm/ddの形式を抽出できるようにしたいと思います.

コード
import re
text_list = ["今日の日付は2022年10月10日です.",
        "今日の日付は2022/6/5です.", 
        "今日の日付は12022年6月5日です.",
        "今日の日付は2022年6月50日です.",
        "今日の日付は2022年21月10日です."]
for text in text_list:
    date_text = re.findall(r'([0-9]+年[0-9]+月[0-9]+日|[0-9]+/[0-9]+/[0-9]+)', text)
    print("抽出テキスト:",date_text[0])
    #このままだと,桁数や有効な日付に対応できていないので条件をつけてマッチさせる.
    ans = re.match(r'[0-9]{4}年(1?[0-9])月([1-3]?[0-9])日|[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}', date_text[0])
    if ans:
        print("日付の抽出結果:",ans.group())
    else:
        print("日付の抽出結果:",ans)
#出力
抽出テキスト: 2022年10月10日
日付の抽出結果: 2022年10月10日
抽出テキスト: 2022/6/5
日付の抽出結果: 2022/6/5
抽出テキスト: 12022年6月5日
日付の抽出結果: None
抽出テキスト: 2022年6月50日
日付の抽出結果: None
抽出テキスト: 2022年21月10日
日付の抽出結果: None
解説

二段階で抽出する形にしています.
一段階目で○○年○○月○○日やyyyy/mm/ddとなっている部分を抽出してきます.
これだけでは年の桁数が5桁以上であったり,ありえない月日のものも抽出されてしまいます.
そこで二段階目である程度ゴミを取り除くようにデータ正規表現を再度使ってふるいにかけています.
まず,年に関しては”[0-9]{4}”で4桁の数字に固定しています.
月に関しては2桁の場合1で固定なので,”(1?[0-9])”で0〜19までの範囲に絞っています.
日付に関しても2桁の場合1〜3に固定されるので.”([1-3]?[0-9])”で0〜39までの範囲に絞っています.
月日に関しては,本来まだあり得ない数字が入る可能性があるのでif文やより細かい正規表現で調整する必要があります.

事例4:住所

住所は,〇〇県〇〇市〇〇区町名○-○○-〇〇 マンション名○○○号室という文字列を抽出したいと思います.

コード
import re
text_list = ["住所:北海道札幌市市中央区北3条西6丁目です.",
            "住所は北海道札幌市中央区北3条西6丁目1番13号です.",
            "住所は東京都新宿区西新宿2-8-1です.", 
            "住所は神奈川県横浜市西区みなとみらい2-2-1 ランドマークタワー101号室です."]
for text in text_list:
    pattern = '[^\u3041-\u309F\s::]+?[都道府県].+[市区].+?[0-9]丁目[0-9]*番?[0-9]*号?(?:.+?[0-9]*号室)?'
    pattern2 = '[^\u3041-\u309F\s::]+?[都道府県].+[市区].+?[0-9]-?[0-9]*-?[0-9]*(?:.+?[0-9]*号室)?'
    ans = re.findall(pattern+"|"+pattern2, text)
    print(ans)
#出力
['北海道札幌市中央区北3条西6丁目']
['北海道札幌市中央区北3条西6丁目1番13号']
['東京都新宿区西新宿2-8-1']
['神奈川県横浜市西区みなとみらい2-2-1\u3000ランドマークタワー101号室']
解説

県庁所在地を例に抽出してみました.
○○県部分に関しては必ず漢字が当てはまるので,”^\u3041-\u309F”でひらがな以外を指定しています.また,空白や”:”などの記号が入るパターンもあるかと思い,”\s::”で左記の記号が含まれないようにしています.
また,”+?”は最小マッチを表しています.今回の場合,”都道府県”のいずれかの文字列の直前までを抽出していることになります.
最後の”(?:.+?[0-9]*号室)?”の部分に関してです.
こちらはマンション名などが記載されているかを判断している部分になります.
“(?: )”を使うことで,括弧内のパターンマッチした部分をキャプチャしないようにすることができます.
よって,”(?:.+?[0-9]*号室)?”は”数字にぶつかるまでの任意の文字が1文字以上 + 任意の数字の繰り返し+号室”という0,1回の繰り返しをキャプチャせずに抽出するということになります.

最後に

今回はユースケース別にpythonの正規表現で抽出するということを試してみました.
正確に抽出するにはどのユースケースもさらに工夫することが必要ですが,正規表現を学ぶにはちょうどいい例になっているのではないかと思います.
参考までにご活用ください.
質問等ございましたら,コメント・問い合わせでお知らせください.

また,下記リンクで詳細に正規表現の扱い方等は載っていますのでより詳細に知りたい方は確認してみてください.

参考文献

コメント

タイトルとURLをコピーしました