Python PR

【Python】正規表現を使って複雑な文字列を操作する方法【reモジュールの使い方】

記事内に商品プロモーションを含む場合があります

この記事では、Python の reモジュール の使い方を解説します。

reモジュール を使うことで正規表現を使った文字列の取得、分割、置換を行うことができます。正規表現を使うので複雑な文字列にも対応可能です。

正規表現については以下の記事を参考にしてください。

【Python】正規表現の書き方を学ぼう!この記事では、Python で正規表現を使う方法を解説します。文字のパターンによってそれが何を表しているかわかる場合があります。そんな文字列は正規表現を使うことで簡単に取得することができます。それでは、正規表現の使い方を見ていきましょう!...

reモジュール は、標準ライブラリです。インポートするだけで使えます。

import re

それでは、reモジュール の使い方を見ていきましょう❗️

マッチオブジェクトの取得

文字列にパターン(正規表現)がマッチすれば、対応したマッチオブジェクトが返されます。マッチオブジェクトについては後述します。

先頭のマッチ[re.match]

re.match(pattern, string, flags=0)

string(文字列) の先頭で pattern(正規表現) にマッチすれば、対応するマッチオブジェクトを返します。

import re

match = re.match('abc', 'abcabc')
print(f'マッチした箇所: {match.group()}')
>> マッチした箇所: abc

先頭でなければマッチしない。

import re

match = re.match('bc', 'abcabc')
print(f'マッチした箇所: {match.group()}')
>> AttributeError: 'NoneType' object has no attribute 'group'

最初のマッチ[re.search]

re.search(pattern, string, flags=0)

string(文字列) の最初に pattern(正規表現) にマッチした箇所に対応するマッチオブジェクトを返します。

import re

match = re.search('abc', 'abcabc')
print(f'マッチした箇所: {match.group()}')
>> マッチした箇所: abc

もちろん、先頭以外の箇所でもマッチします。

import re

match = re.search('bc', 'abcabc')
print(f'マッチした箇所: {match.group()}')
>> マッチした箇所: bc

全体のマッチ[re.fullmatch]

re.fullmatch(pattern, string, flags=0)

string(文字列) の全体が pattern(正規表現) にマッチすれば、対応するマッチオブジェクトを返します。Python 3.4 で追加

import re

match = re.fullmatch('abc', 'abc')
print(f'マッチした箇所: {match.group()}')
>> マッチした箇所: abc

一箇所でも違えばマッチしません。

import re

match = re.fullmatch('ab', 'abc')
print(f'マッチした箇所: {match.group()}')
>> AttributeError: 'NoneType' object has no attribute 'group'

全ての重複しないマッチをイテレータで返す[re.finditer]

re.finditer(pattern, string, flags=0)

string(文字列)中の重複しないマッチに対応した全てのマッチオブジェクトをイテレータとして返します。

import re

matchs = re.finditer('abc', 'abcabc')

# イテレータとして返されるのでfor文で処理
for i, match in enumerate(matchs, 1):
    print(f'{i}回目のマッチ: {match.group()}')
>> 1回目のマッチ: abc
>> 2回目のマッチ: abc

マッチオブジェクト

マッチオブジェクトの bool値 は True です。なので、マッチしたかどうかは以下のように簡単に判定できます。

import re

match = re.match(pattern, string)

if match:
    # マッチオブジェクト有り

マッチした文字列を取得する

group()メソッド を使うことでマッチした箇所の文字列を取得することができます。

import re

match = re.match('.+=.+', 'age=20')
print(f'マッチした箇所: {match.group()}')
# >> マッチした箇所: age=20

# 引数に0を指定しても同じ
print(f'マッチした箇所: {match.group(0)}')
>> マッチした箇所: age=20

グループ化してある場合は、引数にグループのインデックスを指定することでグループごとに取得することができます。

import re

match = re.match('(.+)=(.+)', 'age=20')
print(match.group(1), match.group(2))
>> age 20

# 複数の引数を指定することで、まとめてタプルとして取得可能
print(match.group(1, 2))
>> ('age', '20')

グループにグループ名が指定されている場合は、グループ名を指定することで対応した文字列を取得することができます。

import re

match = re.match('(?P<section>.+)=(?P<value>.+)', 'age=20')
print(match.group('section'), match.group('value'))
>> age 20

groupdict()メソッド を使うことでグループ名を key、マッチを value として格納した辞書を取得できます。

import re

match = re.match('(?P<section>.+)=(?P<value>.+)', 'age=20')
print(match.groupdict())
>> {'section': 'age', 'value': '20'}

groups()メソッド を使えば、マッチしたグループ全てをタプルとして取得できる。

import re

match = re.match('(.+)=(.+)', 'age=20')
print(f'グループ: {match.groups()}')
>> グループ: ('age', '20')

match = re.match('(.+)=(.+)?', 'age=')
# マッチしなかったグループにはNoneが返される
print(f'グループ: {match.groups()}')
>> グループ: ('age', None)

# 引数でデフォルト値を指定できる
print(f'グループ: {match.groups(0)}')
>> グループ: ('age', 0)

マッチのインデックス

マッチした箇所の先頭のインデックスを start()メソッド、末尾のインデックスを end()メソッド で取得することができます。

import re

match = re.match('(.+)=(.+)', 'age=20')
print(f'マッチ: {match.group()}, 先頭: {match.start()}, 末尾: {match.end()}')
>> マッチ: age=20, 先頭: 0, 末尾: 6

引数でグループを指定することができます。

print(f'マッチ: {match.group(1)}, 先頭: {match.start(1)}, 末尾: {match.end(1)}')
>> マッチ: age, 先頭: 0, 末尾: 3

print(f'マッチ: {match.group(2)}, 先頭: {match.start(2)}, 末尾: {match.end(2)}')
>> マッチ: 20, 先頭: 4, 末尾: 6

span()メソッド で先頭と末尾のインデックスを保持したタプルを受け取ることができます。こちらのメソッドも引数でグループを指定可能です。

import re

match = re.match('(.+)=(.+)', 'age=20')
print(f'マッチ: {match.group()}, span: {match.span()}')
>> マッチ: age=20, span: (0, 6)

print(f'マッチ: {match.group(1)}, span: {match.span(1)}')
>> マッチ: age, span: (0, 3)

print(f'マッチ: {match.group(2)}, span: {match.span(2)}')
>> マッチ: 20, span: (4, 6)

全てのマッチを文字列のリストで返す

re.findall()メソッド を使うことで全てのマッチを文字列のリストと取得できます。

re.findall(pattern, string, flags=0)

string(文字列)中のマッチした文字列をリストとして返します。

import re

matchs = re.findall('abc', 'abcabcabc')
print(matchs)
>> ['abc', 'abc', 'abc']

正規表現オブジェクト

正規表現オブジェクトをコンパイルすることで そのオブジェクトから match()メソッド や sertch()メソッド を呼び出すことが可能となります。

同じパターンで何度も処理をしたい場合には、正規表現オブジェクトを生成し、再利用した方が効率的です。

正規表現オブジェクトをコンパイルするには re.compile()メソッド を使います。

re.compile(pattern, flags=0)

例えば、このようなコードは、

obj = re.compile(pattern)
result = obj.search(string)

以下のコードと同等です。

result = re.search(pattern, string)

パターンで分割

re.split()メソッド は、マッチした箇所で分割することができます。

re.split(pattern, string, maxsplit=0, flags=0)

マッチした部分は消えちゃうので注意しましょう。

import re

s = re.split('\W', 'abc,abc,abc')
print(f'リザルト: {s}')
>> マッチした箇所: ['abc', 'abc', 'abc']

maxsplit を指定することで最大分割回数を指定することができます。

import re

s = re.split('\W', 'abc,abc,abc', 1)
print(f'リザルト: {s}')
>> リザルト: ['abc', 'abc,abc']

パターンで置換

re.sub()メソッド は、マッチした箇所を指定した文字列に置換することができます。

re.sub(pattern, repl, string, count=0, flags=0)

repl に置換する文字列を指定します。

import re

s = re.sub('\W', '-', 'abc,abc,abc')
print(f'リザルト: {s}')
>> リザルト: abc-abc-abc

count引数 を指定することで置換する回数を指定できます。

import re

s = re.sub('\W', '-', 'abc,abc,abc', count=1)
print(f'リザルト: {s}')
# >> リザルト: abc-abc,abc

まとめ

この記事では、Python の reモジュール の使い方を解説しました。

正規表現を使うことで複雑な文字列に合わせて色々できます。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ