Pythonにおける正規表現の使い方


ccc

こんにちわ!東京都内でサラリーマンをしているAI・育児ブロガーのCCCです。 AI(人工知能)と子育てに関する記事を執筆しています。 WebシステムをベースとしたAIを活用することで生活をより便利にする方法を紹介し、育児について衣食住における役立つグッズや情報を配信しています。


Pythonにおける正規表現の使い方を教えてください。


ccc

Pythonはオフサイドルールに基づいたオブジェクト指向型のスクリプト言語です。オフサイドルールとは処理のまとまりをブロックごとに字下げをして文の範囲を指定するコーディングルールで、字下げのルールを強制することで可読性が高まり、コードの記述量を少なくできます。数値計算や画像処理、Web開発、ネットワーク、データベースといった専門的なライブラリが豊富で、機械学習やAIの分野で活用されています。


ccc

今回はPythonの使い方として、Pythonにおける正規表現の使い方をサンプルを用いて解説します。

パターンを定義

compile()はパターンを定義するメソッドです。事前にreモジュールをインポートします。

import re
regex1=re.compile("car") #"car"とマッチするパターン
regex2=re.compile("[a-zA-Z]{3}") #アルファベット3文字とマッチするパターン
regex3=re.compile("[0-9a-zA-Z]") #英数字とマッチするパターン

正規表現にマッチした部分の文字列を取得

search()は正規表現にマッチするかどうか調べてMatchクラスのオブジェクトを返すメソッドです。マッチしなかったときはNoneを返します。
group()はマッチした部分の文字列を取得するメソッドです。

正規表現”.”は任意の1文字を意味します。

import re
regex=re.compile("dri.ing")

temp="I love driving a car"
print(regex.search(temp).group())
#driving

メタ文字をエスケープ

アスタリスク(*)など、正規表現で特別な意味を持つ文字をメタ文字といい、単なる文字として扱うときはバックスラッシュ(\)を記述します。

import re
regex=re.compile("\*car")

temp="I love driving a *car"
print(regex.search(temp).group())
#*car

正規表現がマッチする全ての文字列を取得

findall()は正規表現にマッチした部分の文字列を配列に格納するメソッドです。マッチしなかったときは空の配列を返します。

正規表現”\d”は0〜9の数字を意味します。

import re
regex=re.compile("\d{4}年\d{2}月")

temp="2020年12月 2021年01月"
print(regex.findall(temp))
#['2020年12月', '2021年01月']

パターンにマッチしたすべての文字列をイテレータオブジェクトで取得

finditer()はパターンにマッチしたすべての文字列をイテレータオブジェクトで取得するメソッドです。

import re
regex=re.compile("\d{4}年\d{2}月")

temp="2020年12月 2021年01月"
temp2=regex.finditer(temp)

for i in temp2:
 print(i.group())
#2020年12月
#2021年01月

括弧()で囲んだパターンにマッチした部分の文字列を取得することもできます。
group(0)ではパターン全体にマッチした文字列を、group(1)以降ではマッチした部分文字列を取得できます。

import re
regex=re.compile("(\d{4}年)(\d{2}月)")

temp="2020年12月 2021年01月"
temp2=regex.finditer(temp)

for i in temp2:
 print(i.group(0))
 print(i.group(1))
 print(i.group(2))
#2020年12月
#2020年
#12月
#2021年01月
#2021年
#01月

パターンのグループに名前をつける

括弧()で囲ったパターンのグループに名前をつけることができます。
それぞれのパターンの前に”?P<名前>”をつけます。参照するときは、”変数.groups(名前)”と記述します。

import re
regex=re.compile("(?P<yyyy>\d{4}年)(?P<mm>\d{2}月)")

temp="2020年12月"
temp2=regex.finditer(temp)
for i in temp2:
 print(i.group(0))
 print(i.group("yyyy"))
 print(i.group("mm"))
#2020年12月
#2020年
#12月

パターンにマッチした文字列のインデックスを取得

start()とend()はパターンにマッチした文字列の先頭と末尾のインデックスを取得するメソッドです。

import re
regex=re.compile("\d{4}年\d{2}月")

temp="2020年12月"
temp2=regex.finditer(temp)

for i in temp2:
 print(i.group(0))
 print(i.start(0))
 print(i.end(0))
#2020年12月
#0
#8

正規表現を使った区切り文字で分割

spilit()は正規表現を使った区切り文字で文字列を分割できるメソッドです。
正規表現”[ ]”は括弧の中のどれか1文字を意味します。

import re
regex=re.compile("[,.]")

temp="123,456.789"
temp2=regex.split(temp)

for i in temp2:
 print(i)
#123
#456
#789

正規表現にマッチした文字列を別の文字列に置き換える

sub()は正規表現にマッチした文字列を別の文字列に置き換えるメソッドです。
正規表現”|”は複数の文字列のいずれかを意味します。

import re
regex=re.compile("car|truck")

temp="I love driving a car and truck"
print(regex.sub("vehicle", temp))
#I love driving a vehicle and vehicle

括弧()で囲んだパターンにマッチした部分の文字列を”\\数字”で取得することもできます。

import re
regex=re.compile("(\d{4})年(\d{2})月")

temp="2020年12月"
print(regex.sub("\\1年\\2月", temp))
#2020年12月

括弧()で囲んだパターンにマッチした部分の文字列をグループ名で取得することもできます。

import re
regex=re.compile("(?P<yyyy>\d{4})年(?P<mm>\d{2})月")

temp="2020年12月"
print(regex.sub("\g<yyyy>年\g<mm>月", temp))
#2020年12月

関数を使って正規表現にマッチした文字列を置き換えることもできます。
正規表現”[^]”は括弧の中にない1文字を意味します。

def test(i):
return i.group(0).upper()

import re
regex=re.compile("[^car]")

temp="car cat car cat"
print(regex.sub(test, temp))
#car caT car caT

正規表現の略記

正規表現を略して記述することができます。

\d #数字 [0-9]を意味する
\D #数字以外 [^\d]を意味する
\w #英数字とアンダーバー [0-9a-zA-Z_]を意味する
\W #英数字とアンダーバー以外 [^\w]を意味する

正規表現の特殊文字

次のような正規表現の特殊文字があります。

\n #改行
\t #タブ

文字列の先頭や末尾などにマッチする正規表現

文字列の先頭や末尾などにマッチする正規表現があります。

^ #文字列の先頭にマッチ "^abc"
$ #文字列の末尾にマッチ "abc$"
\b #単語の先頭または末尾にマッチ "\babc" "abc\b" "\babc\b"
\B #単語の先頭または末尾以外にマッチ "\Babc" "abc\B" "\Babc\B"

直前の文字を指定回数繰り返す正規表現

直前の文字を指定回数だけ繰り返す正規表現があります。

* #直前の文字を0回以上の繰り返す
+ #直前の文字を1回以上の繰り返す
? #直前の文字が0回または1回出現
{3} #直前の文字を3回繰り返す
{3,} #直前の文字を3回以上繰り返す
{,3} #直前の文字を3回以下繰り返す
{3,6} #直前の文字を3回以上6回以下繰り返す
.* #任意の文字を0回以上繰り返す
(\d{1,3}){3} #1~3文字の数値を3回繰り返す

量を表す正規表現でより多い文字列とマッチする

“+”や”*”など量を表す正規表現を使うと、デフォルトでより多い文字列とマッチしようとします。

import re
regex=re.compile("a.+b")
temp="aabaaab"
print(regex.search(temp).group())
#aabaaab

import re
regex=re.compile("a.*b")
temp="aabaaab"
print(regex.search(temp).group())
#aabaaab

import re
regex=re.compile("\d{1,5}")
temp="123456789"
print(regex.search(temp).group())
#12345

量を表す正規表現でより少ない文字列とマッチする

“+”や”*”などの量を表す正規表現を使うとき、正規表現”?”を記述するとより少ない文字列とマッチします。

import re
regex=re.compile("a.+?b")
temp="aabaaab"
print(regex.search(temp).group())
#aab

import re
regex=re.compile("a.*?b")
temp="aabaaab"
print(regex.search(temp).group())
#aab

import re
regex=re.compile("\d{1,5}?")
temp="123456789"
print(regex.search(temp).group())
#1

正規表現の先読みと後読み

正規表現の先読みと後読みはマッチするかどうか確認はするがマッチした文字列として取得しないときに使います。

先読みの正規表現では取得する文字列を先に記述し、”(?=)”または”(?!)”を後に記述します。
“(?=)”は肯定を表し、”(?!)”は否定を表します。

import re
regex=re.compile("abc(?=def)") #abcの後にdefがあるときマッチ
temp="abcdef"
print(regex.search(temp).group())
#abc

import re
regex=re.compile("abc(?!def)") #abcの後にdefがないときマッチ
temp="abcdez"
print(regex.search(temp).group())
#abc

後読みの正規表現では”(?<=)”または”(?<!)”を前にに記述し、取得する文字列を後に記述します。
“(?<=)”は肯定を表し、”(?<!)”は否定を表します。

import re
regex=re.compile("(?<=abc)def") #defの前にabcがあるときマッチ
temp="abcdef"
print(regex.search(temp).group())
#def

import re
regex=re.compile("(?<!abc)def") #defの前にabcがないときマッチ
temp="abzdef"
print(regex.search(temp).group())
#def