Java正規表現の3種類の数量詞を徹底解説!貪欲・最短・強欲マッチの違い
正規表現で文字の出現回数を指定したい場合に使うのが「数量詞」です。Javaでは、数量詞は大きく分けて貪欲数量詞、最短数量詞、強欲数量詞という3種類がサポートされています。それぞれの動作の違いを理解しておくと、意図した通りのパターンマッチングができるようになります。
1. 貪欲数量詞
貪欲数量詞はデフォルトの数量詞で、「+」や「*」などをそのまま書いたものがこれに該当します。入力文字列からできるだけ多くの文字をマッチさせようとし(最長一致)、もしマッチに失敗した場合は末尾の1文字を手放して再びマッチを試みます。この「戻って再試行する」動作をバックトラックと呼びます。
サンプルコード
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter input text: ");
String input = sc.nextLine();
String regex = "[0-9]+"; // 貪欲数量詞
// パターンオブジェクトを作成
Pattern pattern = Pattern.compile(regex);
// 文字列に対してコンパイル済みパターンを適用
Matcher matcher = pattern.matcher(input);
System.out.println("Matched text: ");
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}実行結果
Enter input text: 45545abc Matched text: 45545
この例では「[0-9]+」が連続する数字をすべてまとめてマッチしていることがわかります。貪欲数量詞は可能な限り長い文字列を1回で取得します。
2. 最短数量詞
最短数量詞は、できるだけ少ない文字数でマッチしようとする非貪欲な数量詞です。まず最初の1文字だけでマッチを試み、失敗した場合は入力文字列からもう1文字追加して再び試みます。貪欲数量詞の直後に「?」を付けると、最短数量詞になります(例:「+?」「*?」)。
サンプルコード
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter input text: ");
String input = sc.nextLine();
String regex = "[0-9]+?"; // 最短数量詞
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}実行結果
Enter input text: 12345678 1 2 3 4 5 6 7 8
同じ「[0-9]」パターンでも「?」を1つ加えるだけで、数字が1文字ずつ個別にマッチするようになりました。これが最短一致の特徴です。
3. 強欲数量詞
強欲数量詞は貪欲数量詞と似ていますが、決定的な違いがあります。最初にできるだけ多くの文字をマッチさせようとする点は同じですが、一度マッチに失敗してもバックトラックを行いません。そのため処理速度が速く、不要な再試行を防げるのが利点です。
貪欲数量詞の直後に「+」を付けると強欲数量詞になります(例:「++」「*+」「?+」)。主な強欲数量詞の一覧は以下の通りです。
X?+: Xの0回または1回(強欲)X*+: Xの0回以上の繰り返し(強欲)X++: Xの1回以上の繰り返し(強欲)X{n}+: Xのn回の繰り返し(強欲)X{n}+: Xのn回以上の繰り返し(強欲)X{n,m}+: Xのn回以上m回以下の繰り返し(強欲)
サンプルコード
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter input text: ");
String input = sc.nextLine();
String regex = "[0-9]++"; // 強欲数量詞
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
System.out.print(matcher.group());
System.out.println();
}
}
}実行結果
Enter input text: 45678 45678
この例では連続する数字全体が一括でマッチされています。強欲数量詞は後続の条件との組み合わせによってはマッチ全体が失敗することもあるため、使用場面には注意が必要です。
3種類の数量詞の比較まとめ
| 種類 | 書き方の例 | 動作 |
|---|---|---|
| 貪欲 | +、*、? | 最長一致を目指し、失敗時はバックトラックして再試行 |
| 最短 | +?、*?、?? | 最少の文字数でマッチし、必要に応じて文字を増やして再試行 |
| 強欲 | ++、*+、?+ | 最長一致を目指すが、一切バックトラックしない |
数量詞の種類を使い分けることで、正規表現のパフォーマンス向上や、より精密なパターン制御が可能になります。特に大量のテキストを処理する場合は、強欲数量詞によるバックトラック回避が有効なケースも多いので、ぜひ覚えておきましょう。
-
Java正規表現で単語の境界(\b)を一致させる方法をわかりやすく解説
Javaの正規表現では、メタ文字「\b」を使用することで、単語の境界(ワードバウンダリ)を一致させることができます。「\b」は、単語構成文字(英字・数字・アンダースコア)と非単語構成文字(空白や記号など)の間にある位置にマッチします。この性質を利用すると、文字列内の単語数のカウントや、各単語の先頭文字の抽出などを簡単に実装できます。例1:単語の境界の数をカウントするimport java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Example {
-
Javaの正規表現を使って文字列からHTMLタグを抽出する方法
Javaのjava.util.regexパッケージには、文字シーケンスの中から特定のパターンを検索するためのさまざまなクラスが用意されています。 このパッケージのPatternクラスは、正規表現をコンパイルした結果を表すクラスです。文字列と正規表現のマッチングを行うために、次の2つのメソッドが提供されています。 compile() − 正規表現を表す文字列を引数として受け取り、Patternクラスのオブジェクトを返します。 matcher() − 対象となる文字列を受け取り、その文字列を現在のPatternオブジェクトが表すパターンと照合するためのMatcherオブジェクトを生成します。