Java正規表現: java.util.regexでパターンマッチングをマスターする
Javaはjava.util.regexパッケージを提供し、正規表現を用いたパターンマッチングを実現します。Javaの正規表現はPerlプログラミング言語のものと非常に似ており、学習も容易です。
正規表現とは
正規表現とは、パターンに保持される特殊な構文を用いて、他の文字列や文字列のセットをマッチングまたは検索するための、特殊な文字シーケンスです。テキストやデータの検索、編集、操作に利用できます。
java.util.regexの主要クラス
java.util.regexパッケージは主に以下の3つのクラスで構成されます。
- Patternクラス - 正規表現のコンパイル済み表現です。publicコンストラクタを持たず、
compile()静的メソッドを呼び出してPatternオブジェクトを取得します。このメソッドは第1引数に正規表現を受け取ります。 - Matcherクラス - パターンを解釈し、入力文字列に対してマッチ操作を実行するエンジンです。同様にpublicコンストラクタを持たず、Patternオブジェクトの
matcher()メソッドを呼び出して取得します。 - PatternSyntaxException - 正規表現パターンの構文エラーを示す非チェック例外です。
キャプチャグループ
キャプチャグループは、複数の文字を単一のユニットとして扱う仕組みです。グループ化したい文字を括弧で囲むことで作成します。例えば、正規表現(dog)は「d」「o」「g」を含む単一のグループを作成します。
キャプチャグループは、左から右へ開き括弧を数えることで番号付けされます。式((A)(B(C)))には、例えば以下の4つのグループがあります。
((A)(B(C)))(グループ1)(A)(グループ2)(B(C))(グループ3)(C)(グループ4)
式に存在するグループ数を知るには、MatcherオブジェクトのgroupCount()メソッドを呼び出します。このメソッドは、Matcherのパターンに存在するキャプチャグループの数をintで返します。
また、グループ0という特殊なグループが常に存在し、これは式全体を表します。このグループはgroupCount()の合計には含まれません。
例: 英数字文字列から数字列を抽出
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main(String args[]) {
// パターンを検索する対象文字列
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
// Patternオブジェクトを作成
Pattern r = Pattern.compile(pattern);
// Matcherオブジェクトを作成
Matcher m = r.matcher(line);
if (m.find()) {
System.out.println("Found value: " + m.group(0));
System.out.println("Found value: " + m.group(1));
System.out.println("Found value: " + m.group(2));
} else {
System.out.println("NO MATCH");
}
}
}
実行結果
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0
正規表現の構文
Javaで利用可能な正規表現メタキャラクタ構文を以下の表にまとめます。
| 部分配列 | 一致する内容 |
|---|---|
| ^ | 行の先頭に一致 |
| $ | 行の末尾に一致 |
| . | 改行を除く任意の1文字に一致。mオプション使用時は改行も含む |
| [...] | 括弧内の任意の1文字に一致 |
| [^...] | 括弧内にない任意の1文字に一致 |
| \A | 文字列全体の先頭 |
| \z | 文字列全体の末尾 |
| \Z | 文字列全体の末尾(許容される最終行終端文字を除く) |
| re* | 直前の式の0回以上の繰り返し |
| re+ | 直前のものの1回以上の繰り返し |
| re? | 直前の式の0回または1回の出現 |
| re{ n} | 直前の式のちょうどn回の出現 |
| re{ n,} | 直前の式のn回以上の出現 |
| re{ n, m} | 直前の式のn回以上m回以下の出現 |
| a| b | aまたはbに一致 |
| (re) | 正規表現をグループ化し、マッチしたテキストを記憶 |
| (?: re) | 正規表現をグループ化するが、マッチしたテキストを記憶しない |
| (?> re) | バックトラックなしで独立したパターンに一致 |
| \w | 単語構成文字に一致 |
| \W | 非単語構成文字に一致 |
| \s | 空白文字に一致。[\t\n\r\f]と同等 |
| \S | 非空白文字に一致 |
| \d | 数字に一致。[0-9]と同等 |
| \D | 非数字に一致 |
| \A | 文字列の先頭に一致 |
| \Z | 文字列の末尾に一致。改行があればその直前 |
| \z | 文字列の末尾に一致 |
| \G | 前回のマッチが終了した位置 |
| \n | キャプチャグループ番号「n」への後方参照 |
| \b | 括弧の外では単語境界、中ではバックスペース(0x08)に一致 |
| \B | 非単語境界に一致 |
| \n, \t, etc. | 改行、キャリッジリターン、タブ等に一致 |
| \Q | \Eまでのすべての文字をエスケープ(クォート) |
| \E | \Qで始まったクォートを終了 |
Matcherクラスのメソッド
インデックスメソッド
入力文字列においてマッチが見つかった正確な位置を示すインデックス値を提供します。
| No. | メソッドと説明 |
|---|---|
| 1 | public int start() - 前回のマッチの開始インデックスを返す |
| 2 | public int start(int group) - 前回のマッチ操作で指定グループが捕捉した部分列の開始インデックスを返す |
| 3 | public int end() - 最後にマッチした文字の次のオフセットを返す |
| 4 | public int end(int group) - 前回のマッチ操作で指定グループが捕捉した部分列の最後の文字の次のオフセットを返す |
検査メソッド
入力文字列を検査し、パターンが見つかるかどうかをbooleanで返します。
| No. | メソッドと説明 |
|---|---|
| 1 | public boolean lookingAt() - リージョンの先頭から入力シーケンスをパターンにマッチさせようとする |
| 2 | public boolean find() - パターンにマッチする入力シーケンスの次の部分列を検索しようとする |
| 3 | public boolean find(int start) - このMatcherをリセットし、指定インデックスから次の部分列を検索しようとする |
| 4 | public boolean matches() - リージョン全体をパターンにマッチさせようとする |
置換メソッド
入力文字列内のテキスト置換に便利なメソッドです。
| No. | メソッドと説明 |
|---|---|
| 1 | public Matcher appendReplacement(StringBuffer sb, String replacement) - 非終端の追加と置換ステップを実装 |
| 2 | public StringBuffer appendTail(StringBuffer sb) - 終端の追加と置換ステップを実装 |
| 3 | public String replaceAll(String replacement) - パターンにマッチする入力シーケンスのすべての部分列を指定置換文字列で置き換え |
| 4 | public String replaceFirst(String replacement) - パターンにマッチする最初の部分列を置換 |
| 5 | public static String quoteReplacement(String s) - 指定文字列のリテラル置換Stringを返す。MatcherクラスのappendReplacementメソッドでリテラル置換sとして機能するStringを生成 |
startメソッドとendメソッドの例
入力文字列内で単語「cat」が出現する回数を数える例です。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "\\bcat\\b";
private static final String INPUT = "cat cat cat cattie cat";
public static void main(String args[]) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
int count = 0;
while (m.find()) {
count++;
System.out.println("Match number " + count);
System.out.println("start(): " + m.start());
System.out.println("end(): " + m.end());
}
}
}
実行結果
Match number 1 start(): 0 end(): 3
Match number 2 start(): 4 end(): 7
Match number 3 start(): 8 end(): 11
Match number 4 start(): 19 end(): 22
この例では単語境界を使用して、「c」「a」「t」がより長い単語の部分文字列でないことを保証しています。また、入力文字列のどこでマッチが発生したかについての有用な情報も提供されます。
startメソッドは、前回のマッチ操作で指定グループが捕捉した部分列の開始インデックスを返し、endは最後にマッチした文字のインデックスに1を加えた値を返します。
matchesメソッドとlookingAtメソッド
両メソッドとも入力シーケンスをパターンにマッチさせようとしますが、matchesは入力シーケンス全体のマッチを要求するのに対し、lookingAtは要求しません。両者は常に入力文字列の先頭から開始します。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
public static void main(String args[]) {
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
System.out.println("Current REGEX is: " + REGEX);
System.out.println("Current INPUT is: " + INPUT);
System.out.println("lookingAt(): " + matcher.lookingAt());
System.out.println("matches(): " + matcher.matches());
}
}
実行結果
Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
lookingAt(): true
matches(): false
replaceFirstメソッドとreplaceAllメソッド
指定された正規表現にマッチするテキストを置換します。名前の通り、replaceFirstは最初の出現を、replaceAllはすべての出現を置換します。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " + "All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
実行結果
The cat says meow. All cats say meow.
appendReplacementメソッドとappendTailメソッド
Matcherクラスはテキスト置換用にappendReplacementとappendTailメソッドも提供します。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoob";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
}
}
実行結果
-foo-foo-foo-
PatternSyntaxExceptionクラスのメソッド
PatternSyntaxExceptionは正規表現パターンの構文エラーを示す非チェック例外です。このクラスは以下のメソッドを提供し、何が間違っていたかを特定するのに役立ちます。
| No. | メソッドと説明 |
|---|---|
| 1 | public String getDescription() - エラーの説明を取得 |
| 2 | public int getIndex() - エラーのインデックスを取得 |
| 3 | public String getPattern() - エラーのある正規表現パターンを取得 |
| 4 | public String getMessage() - 構文エラーの説明とそのインデックス、エラーのあるパターン、パターン内のエラーインデックスの視覚的表示を含む複数行の文字列を返す |
Java
- C# の式、文、ブロック:実践例で徹底理解
- Java演算子をマスター:種類、構文、実践例
- Javaの式、文、ブロックを理解する
- Javaコメント:種類、使い方、ベストプラクティス
- Java拡張forループをマスター:構文、例、ベストプラクティス
- Java文字列をマスター:生成、メソッド、ベストプラクティス
- Javaインターフェース完全ガイド:概念、実装、ベストプラクティス
- Javaのtry-with-resourcesをマスターする:自動リソース管理の仕組みと活用法
- Javaアノテーション完全ガイド:種類、配置場所、実践例
- Javaアサーション完全ガイド:バグ早期発見とコード信頼性の向上
- Javaラムダ式完全ガイド:基礎からStream APIまで