本記事では、正規表現の貪欲(greedy)・非貪欲(non-greedy)マッチについて紹介します。
本記事では、以下の内容を紹介しています。
この記事で分かること
- 貪欲マッチ、非貪欲マッチについて
- 貪欲マッチ、非貪欲マッチのサンプルコード
Pythonの正規表現については、以下の記事も併せて参考にしてみてください。
【Python】正規表現の基本的な使用方法【reモジュール】
【Python】正規表現の具体的な使用例【日付、電話番号、メールアドレス、URL】
【Python】正規表現の特殊シーケンスについて【バックスラッシュ、円マーク】
【Python】reモジュールのcompile関数の使い方
スポンサーリンク
【正規表現】貪欲マッチ、非貪欲マッチについて
正規表現には、*、+、?、{m,n}などの繰り返しを表す記号があります。
これらの記号は、デフォルトでは貪欲(greedy)マッチであり、できる限り長い文字列にマッチしようとします。
以下は、任意の1文字を表す " . " と、0回以上の繰り返しを表す" * "を組み合わせて、a.*cのパターンを検索するサンプルコードです。
import re
s = r'abc abbbc'
pattern = r'a.*c'
res = re.findall(pattern, s)
print(res)
# ['abc abbbc']
検索結果は、 abc abbbc となり、文字列全体にマッチしています。
これは、貪欲マッチで検索したために、できるだけ長い文字列でマッチされたためです。
では、もし、abc、abbbcを分けて検索したい場合はどうすればよいでしょう。
このような場合に使用するのが、非貪欲マッチ(non-greedy)です。
非貪欲マッチにすると、できるだけ短い文字列にマッチするようになります。
非貪欲マッチを指定する場合は、繰り返しを表す記号の後ろに" ? "を記載します。
以下、非貪欲マッチで検索するサンプルコードです。
import re
s = r'abc abbbc'
pattern = r'a.*?c'
res = re.findall(pattern, s)
print(res)
# ['abc', 'abbbc']
検索結果は、 abcと、abbbc となり、2つの文字列が分かれてマッチしています。
以降では、複数のメタ文字について、貪欲・非貪欲マッチのサンプルコードを紹介します。
スポンサーリンク
【正規表現】貪欲マッチ、非貪欲マッチのサンプルコード
ここから、繰り返しを表すメタ文字について、順番に貪欲・非貪欲マッチのサンプルコードを紹介します。
- * : 0回以上繰り返し
- + : 1回以上繰り返し
- ? : 0回または1回繰り返し
- {m, n} : m回~n回繰り返し
* : 0回以上繰り返し
貪欲マッチ(再掲)
import re
s = r'abc abbbc'
pattern = r'a.*c'
res = re.findall(pattern, s)
print(res)
# ['abc abbbc']
非貪欲マッチ(再掲)
import re
s = r'abc abbbc'
pattern = r'a.*?c'
res = re.findall(pattern, s)
print(res)
# ['abc', 'abbbc']
+ : 1回以上繰り返し
貪欲マッチ
import re
s = r'abc abbbc'
pattern = r'a.+c'
res = re.findall(pattern, s)
print(res)
# ['abc abbbc']
非貪欲マッチ
import re
s = r'abc abbbc'
pattern = r'a.+?c'
res = re.findall(pattern, s)
print(res)
# ['abc', 'abbbc']
? : 0回または1回繰り返し
貪欲マッチ
import re
s = r'abbb'
pattern = r'ab?'
res = re.findall(pattern, s)
print(res)
# ['ab']
非貪欲マッチ
import re
s = r'abbb'
pattern = r'ab??'
res = re.findall(pattern, s)
print(res)
# ['a']
正規表現の記号" ? "は、0回または1回の繰り返しを表します。
貪欲マッチの場合は、長い文字列にマッチしようとするので、1回の繰り返しでマッチします。
非貪欲マッチの場合は、0回の繰り返しでマッチしています。
{m, n} : m回~n回繰り返し
貪欲マッチ
import re
s = r'abababababab'
pattern = r'(ab){2,4}'
res = re.finditer(pattern, s)
for r in res :
print(r)
# <re.Match object; span=(0, 8), match='abababab'>
# <re.Match object; span=(8, 12), match='abab'>
非貪欲マッチ
import re
s = r'abababababab'
pattern = r'(ab){2,4}?'
res = re.finditer(pattern, s)
for r in res :
print(r)
# <re.Match object; span=(0, 4), match='abab'>
# <re.Match object; span=(4, 8), match='abab'>
# <re.Match object; span=(8, 12), match='abab'>
正規表現の記号" {2, 4} "は、2回~4回の繰り返しを表します。
上記のサンプルコードでは、
貪欲マッチの場合は、(ab)のグループについて4回、2回の繰り返し
非貪欲マッチの場合は、(ab)のグループについて2回、2回、2回の繰り返し
でマッチしています。
正規表現に関しては、他にも使用方法をまとめています。併せて参考にしてみてください。
【Python】正規表現の基本的な使用方法【reモジュール】
【Python】正規表現の具体的な使用例【日付、電話番号、メールアドレス、URL】
【Python】正規表現の特殊シーケンスについて【バックスラッシュ、円マーク】
【Python】reモジュールのcompile関数の使い方
スポンサーリンク