検索
連載

[解決!Python]re.findall関数と正規表現を使って文字列から部分文字列を抽出するには解決!Python

Pythonの正規表現モジュール(re)が提供するre.findall関数を使って、文字列からパターンにマッチした部分を抽出する方法を紹介する。同様な処理を行うre.finditer関数も取り上げる。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「解決!Python」のインデックス

連載目次

* 本稿は2021年3月5日に公開された記事をPython 3.12.1で動作確認したものです(確認日:2024年2月1日)。


import re

s = 'id: deep, mail: deep@foo.com, tel: 03-0123-4567'

r = re.findall('\w+:', s)  # 「英数字:」を抽出
print(r)  # ['id:', 'mail:', 'tel:']

r = re.findall('ba[rz]', s)
print(r)  # []  # マッチする部分がなければ空のリストが返される

# パターンにかっこで囲んだグループがあれば、それらにマッチしたものを
# 要素とするリストが返される
r = re.findall('(\w+):', s)  # 「英数字:」の「英数字」だけを抽出
print(r)  # ['id', 'mail', 'tel']

# パターンに複数のグループがあれば、タプルのリストが返される
r = re.findall('(\w+): ([-\w\s@.]+)', s)  # キーと値を抽出
print(r)  # [('id', 'deep'), ('mail', 'deep@foo.com'), ('tel', '03-0123-4567')]
d = dict(r)
print(d)  # {'id': 'deep', 'mail': 'deep@foo.com', 'tel': '03-0123-4567'}

# グループ(かっこ)をネストさせる
r = re.findall('((\w+)@([-\w.]+))', s)
print(r)  # [('deep@foo.com', 'deep', 'foo.com')]

# re.finditer関数はMatchオブジェクトを反復するイテレータを返す
r = re.finditer('(\w+): ([-\w\s@.]+)', s)
for m in r:
    print(f'group(0): {m.group(0)}, ', end='')
    print(f'group(1): {m.group(1)}, group(2): {m.group(2)}')
# 出力結果:
# group(0): id: deep, group(1): id, group(2): deep
# group(0): mail: deep@foo.com, group(1): mail, group(2): deep@foo.com
# group(0): tel: 03-0123-4567, group(1): tel, group(2): 03-0123-4567


re.findall関数

 Pythonが標準で提供しているreモジュールを使うと正規表現のマッチング処理を行える。このうち、文字列から部分文字列を抽出するには幾つかの関数が使える。本稿では、re.findall関数とre.finditer関数を紹介する。

 re.findall関数を呼び出す際には、第1引数に正規表現パターンを、第2引数に文字列を指定する。文字列中でパターンにマッチした文字列(やそれらを格納するタプル)を要素とするリストとなる。

 以下に例を示す。

import re

s = 'id: deep, mail: deep@foo.com, tel: 03-0123-4567'

r = re.findall('\w+:', s)  # 「英数字:」を抽出
print(r)  # ['id:', 'mail:', 'tel:']


 この例では、re.findall関数の第1引数に「\w+:」というパターンを、第2引数に「id: deep, mail: deep@foo.com, tel: 03-0123-4567」という文字列を渡している。「\w+:」は「1文字以上の英数字」に続けてコロン「:」を意味するので、文字列の中では「id:」「mail:」「tel:」にマッチする。そのため、戻り値はこれらを要素とするリストとなっている。

 なお、パターンにマッチする部分がないときには、空のリストが返される。

r = re.findall('ba[rz]', s)
print(r)  # []


 パターン中にかっこ「()」が含まれている場合には、そのかっこによって形成されるグループを要素とするリストが返送される。以下に例を示す。

r = re.findall('(\w+):', s)  # 「英数字:」の「英数字」だけを抽出
print(r)  # ['id', 'mail', 'tel']


 この例では第1引数に渡すパターンが「(\w+):」となっている。このときには、かっこ内の正規表現「\w+」にマッチする部分がリストの要素となる。コロンは要素には含まれていないことに注目しよう。

 パターンに複数のグループが含まれている場合には、それらにマッチする部分を要素とするタプルが戻り値であるリストの要素となる。以下に例を示す。

r = re.findall('(\w+): ([-\w\s@.]+)', s)  # キーと値を抽出
print(r)  # [('id', 'deep'), ('mail', 'deep@foo.com'), ('tel', '03-0123-4567')]


 この例では、かっこで囲まれた部分(グループ)が2つあり、パターンが少し長くなっている。1つ目のグループは「(\w+)」であり、これは上で見た通り、「id」「mail」「tel」にマッチする。これらのグループに続けてコロンと半角空白文字があり、その後に次のパターン「([-\w\s@.]+)」がある。こちらはマイナス記号/英数字/空白文字/アットマーク「@」/ピリオド「.」のいずれかが1文字以上連続する部分にマッチする。簡単にいえば、「id: 」の後の英字(deep)、「mail: 」の後のメールアドレス(deep@foo.com)、「tel: 」の後の電話番号(03-1234-5678)が2つ目のパターンにマッチする(全体としては「id: deep」といった部分にマッチする)。

 パターンが複数あるときには、マッチした各文字列を格納するタプルを要素とするリストが返送されるので、その結果は「[('id', 'deep'), ('mail', 'deep@foo.com'), ('tel', '03-0123-4567')]」となる。こうして文字列からキーと値を抽出できたら、以下のようにして、その情報を辞書に登録するといった使い方も可能だ。

d = dict(r)
print(d)  # {'id': 'deep', 'mail': 'deep@foo.com', 'tel': '03-0123-4567'}


 グループがネストしているときには、外側のグループの内容と内側のグループの内容を格納するタプルを要素とするリストが返される。以下に例を示す。

r = re.findall('((\w+)@([-\w.]+))', s)
print(r)  # [('deep@foo.com', 'deep', 'foo.com')]


Copyright© Digital Advantage Corp. All Rights Reserved.

ページトップに戻る