『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

貪欲マッチと非貪欲マッチ

複数文字のパターンマッチ

() は複数文字のパターンをまとめてグループにします。たとえば、(けほ)+けほ の 1 回以上の繰返しを意味します。

# PYTHON_REGEX_MATCH_GROUP

# 正規表現オブジェクトを作成
regex = re.compile(r'(けほ)+')

# 検索対象となる文字列を作成
line = "「最近、ちょっと風邪気味で。けほけほけほ」"

# sentenceを検索
s = regex.search(line)

print(s)
# <_sre.SRE_Match object; span=(14, 20), match='けほけほけほ'>

グループを複数設定することもできます。たとえば、(…)-(…)
523-268‘、’417-109‘ などの文字列にマッチします。matchオブジェクトの group()メソッド の引数に 0 を渡すと、マッチした文字列全体を取得します。引数に 1 を渡すとグループ 1 に、2 を渡すとグループ 2 にマッチした文字列を取得することができます。

# In[2]

# 正規表現オブジェクトを作成(マルチラインを設定)
regex = re.compile(r'(...)-(...)')

expr = "523-268=255"

# 適合した文字列全体を取得
g0 = regex.search(expr).group()

# グループ1に適合した文字列を取得
g1 = regex.search(expr).group(1)

# グループ2に適合した文字列を取得
g2 = regex.search(expr).group(2)

print("適合した文字列全体", g0)
print("グループ1に適合した文字列", g1)
print("グループ2に適合した文字列", g2)

# 適合した文字列全体 523-268
# グループ1に適合した文字列 523
# グループ2に適合した文字列 268

複数候補のパターンマッチ

メタ文字 | を使うと、複数候補のいずれかにマッチするような正規表現をつくることができます。これは似たような意味をもつ単語をまとめて検索するときなどに使用します。たとえば、’おはよう|おはよー|おっはよ~‘ という正規表現は、文章中に
 
おはよう
おはよー
おっはよ~
 
のうち、いずれかの文字列が1つでもあればマッチします。

# In[3]

# 正規表現オブジェクトを作成
regex = re.compile(r'おはよう|おはよー|おっはよ~')

# 検索対象となる文字列を作成
sentence = "「沙希ちゃん、おはよー!」\n\
「おはよう。小春はいつも朝から元気だね」\n\
「だってさ~。こはるは元気だけが取り柄だし~」\n\
「うん。確かにそうだね」\n\
「そこは否定しろ~!」"

# sentenceを検索して適合した文字列をすべて取得
f = regex.findall(sentence)

print(f)
# ['おはよー', 'おはよう']

|() を組合わせることもできます。この場合、() の外側に添えたパターンは複数候補に共通するパターンと認識されます。たとえば、’^(「おはよう|「おはよー|「おっはよ~)‘という正規表現は、文字列の先頭 (フラグに MULTILINE を設定した場合は行の先頭) に
 
「おはよう
「おはよー
「おっはよ~
 
のいずれかの文字があるパターンを意味します。

# In[4]

# 正規表現オブジェクトを作成(マルチラインを設定)
regex = re.compile(r'^(「おはよう|「おはよー|「おっはよ~)', re.M)

# 検索対象となる文章を作成
sentence = "「おっはよ~、沙希ちゃん」\n\
「おはよう」\n\
「今日は良い天気だから、きっと何か良いことあるよね~」\n\
「...... 小春の頭の中は、いつも快晴なんだろうね」"

# sentenceを検索
f = regex.findall(sentence)

print(f)
# ['「おっはよ~', '「おはよう']

貪欲マッチと非貪欲マッチ

(ほ){2,5} という正規表現オブジェクトは、 が 2 回以上 5 回以下の連続する文字列にマッチします。つまり、この正規表現を使って おほほほほほ という文字列を検索すると
 
ほほ
ほほほ
ほほほほ
ほほほほほ
 
にマッチするはずですが、search()メソッドなどを使うと、ほほほほほ にマッチしたと返ってきます。

# PYTHON_REGEX_GREEDY

# In[1]

# 正規表現オブジェクトを作成
regex = re.compile(r'(ほ){3,5}')

# 検索対象文字列
line = 'おほほほほほ'

# lineを検索
s = regex.search(line)

# 適合した文字列を取得
g0 = s.group()

print(s)
print(g0)
# <_sre.SRE_Match object; span=(1, 6), match='ほほほほほ'>
# ほほほほほ

このように、Python の正規表現は、複数候補の中から最も長い文字列にマッチします。これを 貪欲マッチ (greedy match) とよびます。しかし正規表現の後ろに ? を添えると、最も短い文字列にマッチするようになります。

# In[2]

# 正規表現オブジェクトを作成(非貪欲マッチ)
regex = re.compile(r'(ほ){2,5}?')

# 検索対象文字列
line = 'おほほほほほ'

# lineを検索
s = regex.search(line)

# 適合した文字列を取得
g1 = s.group()

print(s)
print(g1)

# <_sre.SRE_Match object; span=(1, 3), match='ほほ'>
# ほほ

これを 非貪欲マッチ (non greedy match) とよびます。

コメント