Pythonと正規表現で文字列を抽出する方法【reモジュールの使い方】

Pythonで正規表現を扱うreモジュールの基本的な使い方を解説します。

Pythonと正規表現で文字列を抽出する方法【reモジュールの使い方】

Pythonで正規表現を扱うreモジュールを用いて、文字列から特定のパターンを抽出する方法をまとめます。reモジュールの基本的な使い方を解説したあとに、Pythonでよく利用する正規表現のパターンについても列挙します。

Pythonのstr型のメソッドを用いた基本的な文字列の抽出方法については以下の記事にまとめています。

Pythonのreモジュールとは?

reモジュールは、Pythonにおいて正規表現を使用するためのモジュールです。正規表現とは、文字列を解析し、特定のパターンにマッチする部分を抽出するための記法のことを指します。

reモジュールには、文字列を抽出するメソッドの他にも、文字列を分割するsplit()や、文字列を置換するsub()などの便利な関数が用意されています。この記事では、文字列を抽出する方法について具体例を用いて解説します。

正規表現で文字列を置換する方法については、以下の関連記事にまとめています。

reモジュールの基本的な使い方

reモジュールを使用するには、まずimport reでモジュールをインポートします。

次に、正規表現を表す文字列を定義します。正規表現文字列内には、特殊文字やメタ文字が含まれることがあります。これらの文字は、特別な意味を持ち、文字列の検索や置換などの操作を行う際に反映されます。Pythonでよく利用される正規表現の記法に関しては、この記事の一番下にまとめてあります

例えば、以下のように、文字列中に含まれる数字を抽出することができます。

import re

string = "The price is $19.99"

# 数字を表す正規表現を定義する
pattern = r'\$(\d+\.\d+)'

# search()関数を使用して、文字列から数字を抽出する
match = re.search(pattern, string)

# group()関数を使用して、マッチした部分を取得する
price = float(match.group(1))

print(price)
# 19.99

注意点として、正規表現を使用する際には、特殊文字やメタ文字が正しくエスケープされていることを確認する必要があります。また、文字コードや文字セットについても注意する必要があります。

正規表現のパターンをコンパイルして処理を効率化する(compile)

実はPythonで正規表現を扱う際には、2つの使い方があります。

1つ目は、上記で説明した、reモジュールのsearch()match()などの関数を使用する方法です。この方法では、正規表現を文字列として直接渡すことで、文字列を解析し、特定のパターンにマッチする部分を抽出することができます。

2つ目の方法は、reモジュールのcompile()メソッドを使用する方法です。この方法では、まずcompile()メソッドを使用して、正規表現を表すオブジェクトを生成します。生成されたオブジェクトには、正規表現を解析し、特定のパターンにマッチする部分を抽出するためのメソッドが用意されています。

先ほどと同じ例で、compile()メソッドを利用したパターンを見てみましょう。

import re

string = "The price is $19.99"

# 数字を表す正規表現を定義する
pattern = r'\$(\d+\.\d+)'

# compile()メソッドを使用して、正規表現を表すオブジェクトを生成する
regex = re.compile(pattern)

# 正規表現Patternオブジェクト
print(type(regex))
# <class 're.Pattern'>

# search()メソッドを使用して、文字列から数字を抽出する
match = regex.search(string)

# group()メソッドを使用して、マッチした部分を取得する
price = float(match.group(1))

print(price)
# 19.99

使い方については、前述の関数を使用する方法と比べてほとんど変わりません。ただし、compile()メソッドを使用する場合は、まず正規表現を表すオブジェクトを生成する必要があるため、少し記述量が増えます。

compile()メソッドを使用するメリットとしては、複数回同じ正規表現を使用する場合には、正規表現の解析を1回だけで済ませることができるため、実行速度が向上する点があげられます。また、compile()メソッドを使用することで、正規表現に対するオプションを指定することができるため、より詳細な制御が可能になります。特定のパターンを何度も解析する場合には、最初にcompile()メソッドでパターンを登録しておくと良いでしょう。

文字列の先頭からマッチしたら抽出する(match)

reモジュールのmatch()メソッドは、正規表現を使用して文字列の先頭からマッチするかどうかを調べるためのメソッドです。

match()メソッドは、次のように使用します。

import re

# 正規表現を定義する(連続した数字のパターン)
pattern = r'\d+'

# match()メソッドを使用して、文字列の先頭からマッチするかどうかを調べる
match = re.match(pattern, '123abc')

# マッチした場合は、Matchオブジェクトが返される
if match:
    print(match.group())
    # 123

# マッチしない場合は、Noneが返される
match = re.match(pattern, 'abc123')
print(match)
# None

上記の例では、正規表現\d+は、数字を表します。そのため、match()メソッドは、文字列の先頭が数字である場合にのみマッチします

match()メソッドで検索し、マッチした場合にはMatchオブジェクトが返されます。

Matchオブジェクトには、次のようなメソッドが用意されています。

  • group(): マッチした部分を文字列として取得する。
  • groups(): マッチした部分をタプルで取得する。正規表現中にカッコで囲んだ部分が複数ある場合に有効。
  • start(): マッチした部分の開始位置を取得する。
  • end(): マッチした部分の終了位置を取得する。
  • span(): マッチした部分の開始位置と終了位置をタプルで取得する。

例えば、次のようにして、文字列中に含まれる数字を抽出することができます。

import re

string = "123abc"

# 数字を表す正規表現を定義する
pattern = r'\d+'

# match()関数を使用して、文字列から数字を抽出したMatchオブジェクトを取得
match = re.match(pattern, string)

# group()関数を使用して、マッチした部分を文字列として取得する
num = match.group()
print(num)
# 123

# start()関数を使用して、マッチした部分の開始位置を取得する
start = match.start()
print(start)
# 0

# end()関数を使用して、マッチした部分の終了位置を取得する
end = match.end()
print(end)
# 3

# span()関数を使用して、マッチした部分の開始位置と終了位置を取得する
span = match.span()
print(span)
# (0, 3)

文字列全体からマッチした部分を抽出する(search)

reモジュールのsearch()メソッドは、正規表現を使用して文字列中からマッチする部分を検索するためのメソッドです。

search()メソッドは、文字列中から最初にマッチした部分のみを返します。つまり、文字列中に複数のマッチする部分がある場合でも、最初の1つのみを返します。

search()メソッドは、次のように使用します。

import re

# 正規表現を定義する
pattern = r'\d+'

# search()メソッドを使用して、文字列中からマッチする部分を検索する
match = re.search(pattern, 'abc123def456')

# マッチした場合は、Matchオブジェクトが返される
# 文字列中から、パターンにマッチした最初の文字が取得できる
if match:
    print(match.group())
    # 123

# マッチしない場合は、Noneが返される
match = re.search(pattern, 'abcdef')
print(match)
# None

上記の例では、正規表現\d+は、数字を表します。そのため、search()メソッドは、文字列中に数字が含まれる場合にのみマッチします。

文字列全体がマッチしたら抽出する(fullmatch)

reモジュールのfullmatch()メソッドは、正規表現を使用して文字列全体がマッチするかどうかを調べるためのメソッドです。

fullmatch()メソッドは、次のように使用します。

import re

pattern = r'\d+'

# fullmatch()メソッドを使用して、文字列がマッチするかどうかを調べる
match = re.fullmatch(pattern, '123')

# マッチした場合は、Matchオブジェクトが返される
if match:
    print(match.group())
    # 123

# マッチしない場合は、Noneが返される
match = re.fullmatch(pattern, 'abc123')
print(match) 
# None

マッチした部分すべてをリストで抽出する(findall

reモジュールのfindall()メソッドは、正規表現を使用して文字列中から複数のマッチする部分を検索するためのメソッドです。findall()メソッドの戻り値はMatchオブジェクトではなくリストになるので気をつけてください。

findall()メソッドは、次のように使用します。

import re

pattern = r'\d+'

# findall()メソッドを使用して、文字列中から複数のマッチする部分を検索する
matches = re.findall(pattern, 'abc123def456')

# マッチした部分をリストで取得する
print(matches)
# ['123', '456']

# マッチしなければ、空の配列を返す
matches = re.findall(pattern, 'abcdef')

print(matches)
# []

マッチした部分すべてをイテレータで抽出する(finditer)

reモジュールのfinditer()メソッドは、正規表現を使用して文字列中から複数のマッチする部分を検索するためのメソッドです。取得したデータは、Matchオブジェクトを要素として持ったイテレータになります。

finditer()メソッドは、次のように使用します。

import re

# 正規表現を定義する
pattern = r'\d+'

# finditer()メソッドを使用して、文字列中から複数のマッチする部分を検索する
matches = re.finditer(pattern, 'abc123def456')

print(matches)
# <callable_iterator object at 0x7f8ee9f35c70>

# マッチした部分をイテレータで取得する
# それぞれの要素はMatchオブジェクト
for match in matches:
    print(match.group())
    # 123
    # 456

finditer()メソッドは、文字列中からマッチする部分を反復処理できるイテレータを返します。つまり、for文を使用してそれぞれの要素にアクセスすることができます。イテレータは要素を一つずつ取り出していくため、最後まで取り出したら空になることに気をつけてください。

Pythonでよく利用する正規表現パターン

Pythonの文字列を扱う際に頻出する正規表現パターンをまとめました。実際に使用する正規表現はこれらを組み合わせた複雑なものである場合が多いですが、これらの基本的な表現を覚えていれば、読み取ることはできるようになります。

  1. \d: 数字を表す文字クラス。例えば、59にマッチします。
  2. \w: 英数字を表す文字クラス。例えば、cYにマッチします。
  3. \s: 空白文字を表す文字クラス。文字列中の空白にマッチします。
  4. .: 任意の1文字を表す文字クラス。例えば、a.bは「aに続いて任意の1文字、そのあとb」という意味です。
  5. *: 直前の文字が0回以上繰り返したものを表す修飾子。例えば、a*は「aが0回以上繰り返したもの」という意味で、aaabcdからはaaaにマッチします。
  6. +: 直前の文字が1回以上繰り返したものを表す修飾子。例えば、a+は「aが1回以上繰り返したもの」という意味で、aaabcdからはaaaにマッチします。
  7. ?: 直前の文字が0回または1回繰り返したものを表す修飾子。例えば、a?は「aが0回または1回繰り返したもの」という意味で、aaabcdからはaにマッチします。
  8. {n}: 直前の文字がn回繰り返したものを表す修飾子。例えば、a{2}は「aが2回繰り返したもの」という意味で、aaabcdからはaaにマッチします。
  9. {n,m}: 直前の文字がn回からm回繰り返したものを表す修飾子。例えば、a{2,4}は「aが2回から4回繰り返したもの」という意味で、aaabcdからはaaaにマッチします。
  10. ^: 行頭を表す文字クラス。例えば、^aは「行頭がaである」という意味で、aaabcdからはaにマッチします。
  11. $: 行末を表す文字クラス。例えば、a$は「行末がaである」という意味で、aaabcdからはaaaにマッチします。
  12. |: OR演算子。複数のパターンのいずれかにマッチするものを表すことができます。例えば、a|bは「aまたはb」という意味です。
  13. [...]: 文字クラスを指定するためのエスケープシーケンス。例えば、[abc]は「aまたはbまたはc」という意味です。
  14. [^...]: NOT演算子を使った文字クラスを指定するためのエスケープシーケンス。例えば、[^abc]は「aでもbでもcでもない」という意味です。
  15. (...): グループ化を行うためのエスケープシーケンス。例えば、(abc)は「abcというグループ」という意味です。