
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