キャプチャグループを設定してパターンの一部にマッチした文字列を取得する

正規表現のパターンの中にキャプチャグループを設定することで、パターン全体にマッチした文字列とは別に、パターンの中の一部分にマッチした文字列を取得することができます。ここでは Python の正規表現でキャプチャグループを利用する方法について解説します。

(Last modified: )

キャプチャグループの設定とキャプチャの取得(|)

正規表現のパターンの中でキャプチャグループを設定するには、設定したい部分を括弧()で囲んでください。

r'abc(def)ghi'

ここで使用する括弧はグループ化の時に指定した括弧と同じものです。グループ化のためにパターンの一部を括弧で囲うと、キャプチャグループもあわせて設定されます。

例えば次のパターンを見てください。

r'\d{3}-\d{4}'

文字列 '郵便番号は 123-4567 です' はこのパターンにマッチし、パターン全体がマッチする文字列は 123-4567 です。この時、パターンの中の \d{4} の部分にマッチした部分だけを取得するにはキャプチャグループを設定します。キャプチャグループを設定するには、パターンの中の設定したい部分を括弧で囲います。

r'\d{3}-(\d{4})'

これで文字列がパターンにマッチした時、パターン全体に対してマッチした文字列 123-4567 とは別に、キャプチャグループの部分にマッチした 4567 を取得することができます。キャプチャグループにマッチした文字列をキャプチャと呼びます。

キャプチャグループは 1 つのパターンの中に複数設定することができます。

r'(\d{3})-(\d{4})'

複数のキャプチャグループを設定した場合は、前から順番にキャプチャグループ 1 、キャプチャグループ 2 のように設定され、あとからキャプチャグループのインデックスを指定してキャプチャされた文字列を参照します。

サンプルコード

簡単なサンプルで試してみます。

import re

pattern = re.compile(r'(\d{3})-(\d{4})')
msg = '郵便番号は 123-4567 です。';

result = pattern.search(msg)
print(result.group(0))
>> 123-4567
print(result.group(1))
>> 123
print(result.group(2))
>> 4567

キャプチャを行わないキャプチャグループを設定する

グループ化のための括弧であってもパターンの中で括弧()で囲われるとキャプチャグループが設定されます。キャプチャを利用する予定がない場合で、明示的にキャプチャを行いたくない場合には括弧()ではなく次のように記述することでキャプチャを行わないキャプチャグループを設定できます。

(?:パターン)

「(」と「)」で囲う代わりに「(?:」と「)」で囲います。この書式で囲んだ場合はグループ化としての機能は同じですがキャプチャは行われません。キャプチャグループの値を繰り返し処理などで順に取得したい場合などに、キャプチャが目的ではないグループに対して使用すると便利です。

サンプルコード

簡単なサンプルで試してみます。

import re

pattern = re.compile(r'製品(?:Code|コード):([A-Z]{2})-(\d{2})')
msg = '製品コード:AZ-07';

result = pattern.search(msg)
print(result.group(1))
>> AZ
print(result.group(2))
>> 07

今回の場合、 3 つのキャプチャグループが設定されていますが、最初のキャプチャグループはキャプチャを行わないように設定したため、キャプチャを順に取得すると 2 つ目のキャプチャグループと 3 つ目のキャプチャグループのキャプチャを取得しました。

名前付きキャプチャグループを使用する

名前付きキャプチャグループを利用すると、キャプチャグループ毎に名前を設定し、インデックスではなく名前を使ってキャプチャした値を参照することができます。書式は次の通りです。

(?P<グループ名>パターン)

通常のキャプチャグループでは、 マッチオブジェクトの group メソッドの引数にキャプチャグループのインデックスを指定することでキャプチャグループのキャプチャした値を参照してきました。名前付きキャプチャグループの場合は、 group メソッドの引数にキャプチャグループの名前を指定してキャプチャした値を参照できます。

マッチオブジェクト.group('グループ名')
サンプルコード

簡単なサンプルで試してみます。

import re

pattern = re.compile(r'製品コード:(?P<section>[A-Z]{2})-(?P<code>\d{2})')
msg = '製品コード:JP-82';

result = pattern.search(msg)
print(result.group('section'))
>> JP
print(result.group('code'))
>> 82

キャプチャした値と同じ値にマッチするパターン

パターンの中でキャプチャグループを設定した場合、キャプチャグループでマッチした値を同じパターン内から参照し、既にキャプチャした値と同じ値にマッチするようにパターンに記述することができます。

参照する場合は、キャプチャ1の値を参照するには \1 、キャプチャ2の値を参照するには \2 のようにパターン内に記述します。

\キャプチャ番号

次のパターンでは 1 番目のキャプチャグループでキャプチャした値を後から参照しています。

r'(ABC).*\1'

この場合、 ABC から始まり、任意の文字が 0 回以上続いたあと、 1 番目のキャプチャグループでキャプチャした値と同じ値が続くパターンとなります。 1 番目のキャプチャグループでキャプチャした値は ABC なので r'ABC.*ABC' というパターンと同じです。

簡単なサンプルで試してみます。

import re

pattern = re.compile(r'<(.+)>.*</\1>')
msg = 'AAA <div>BBB<span>CCC</span>DDD</div>EE';

result = pattern.search(msg)
print(result.group(0))
>> <div>BBB<span>CCC</span>DDD</div>

今回のサンプルでは最初に見つかったタグ(今回の場合は <div> )と同じ名前の閉じタグ(今回の場合は </div> )で囲まれた文字列にマッチしています。同じ名前の閉じタグを探すためにキャプチャした値を後から参照しています。

-- --

Python の正規表現でキャプチャグループを利用する方法について解説しました。

( Written by Tatsuo Ikura )

Profile
profile_img

著者 / TATSUO IKURA

プログラミングや開発環境構築の解説サイトを運営しています。