PatternとMatcherによる正規表現処理
独特なPatternとMatcherの使い方をまとめました。
Java | Java SE 8 |
概要
Java標準ライブラリで正規表現処理を行う場合、「java.util.regex」パッケージのPatternとMatcherがベースになる。ただしユーティリティも用意されているので問題なければその方が楽。こちら

クラス | 概要 |
---|---|
Pattern |
コンパイル済みの正規表現 |
Matcher |
Patternを特定の文字列に適用するときのステートを保持する |
正規表現を表すPatternクラスとそれに対応した問い合わせの結果を保持するMatcherクラスを別々にすることで、概念的に分けている。概念的にはスッキリしているが使いやすいかはどうかは別。
Patternはイミュータブルであるが、MatcherはJDBCのResultSetのように内部でポインターを進ませる形で適用結果を取得していくので注意する。
基本手順としては次のような流れ。
-
正規表現パターンをコンパイルしてPatternオブジェクトを生成
-
正規表現を適用したいテキストを渡して、Matcherオブジェクト生成
-
Matcherにより、検索・置換・分割などを行う
Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("aaaaab");
// マッチしているのでtrueが返る
boolean matchResult = matcher.matches();
Patternの生成
Patternの生成については次のことをおさえておきたい。
-
Pattern#compile()のファクトリから生成を行う。
-
正規表現文字列を渡して、コンパイルされる。
-
正規表現文字列が不正の場合はPatternSyntaxException。
-
-
正規表現文字列の他にオプションを指定することができる。
-
ビット・マスクなので複数オプションは「|」演算で指定する。
-
-
Patternオブジェクトはイミュータブルであるため、マルチスレッドでも使い回し可能。
Pattern pattern = Pattern.compile("a*b", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
オプション | 説明 |
---|---|
CASE_INSENSITIVE |
ASCIIの大文字と小文字を無視する。 |
MULTILINE |
複数行モードを有効にします。 |
DOTALL |
「.」を全ての文字列とマッチさせる。 |
UNICODE_CASE |
ASCII以外の大文字と小文字を無視する。 |
CANON_EQ |
正規等価を有効にします。 |
UNIX_LINES |
Unixライン・モードを有効にします。 |
LITERAL |
パターンのリテラル構文解析を有効にします。 |
UNICODE_CHARACTER_CLASS |
定義済みの文字クラスとPOSIX文字クラスのUnicodeバージョンを使用可能にします。 |
COMMENTS |
パターン内で空白とコメントを使用できるようにします。 |
Matcherオブジェクトの生成と使い方
基本的には次のようなかたち。
String input = "cat dog cap";
Pattern pattern = Pattern.compile("ca.");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
String matched = matcher.group();
System.out.printf("[%s] がマッチしました。 Pattern:[%s] input:[%s]\n", matched, pattern, input);
}
出力
[cat] がマッチしました。 Pattern:[ca.] input:[cat dog cap]
[cap] がマッチしました。 Pattern:[ca.] input:[cat dog cap]
MatcherオブジェクトはPattern#matcher()メソッドに適用したい文字列(文章)を渡すことで生成できる。これで正規表現を適用した状況になり、その後は「抽出」「置換」といった処理を行うことになる。
MatcherオブジェクトはJDBCのResultSetのようなイメージ。正規表現の場合は複数回マッチされることが考えられるので、上記の例のようにwhile文などで回す。Matcherオブジェクトは内部でポインターを持っているので、find()がtrueを返すのと同時に内部ポインターが進み、次はその位置からfind()のマッチングを行う。そしてマッチしなくなったときにfalseが返る。
3種類の正規表現マッチメソッド
find()も含め次の3種類の正規表現マッチメソッドが用意されている。全てbooleanを返すがパターンの適用範囲がそれぞれ違う。
メソッド | 概要 |
---|---|
find() |
パターンが(どこかの)部分とマッチした場合、true。 |
lookingAt() |
パターンが先頭からマッチした場合、true。 |
matches() |
パターンが全体とマッチした場合、true。 |
正規表現の検索処理を想像した場合find()の動きがデフォルトっぽく思えるが、lookingAt()やmatches()も場面によっては有効なので違いを把握して使う。
これらの3種類のメソッドはマッチしたモノがあったか否かをbooleanで返すだけなので、実際にマッチした文字列はMatcher#group()などから取得する。
String input = "http://example.com/";
Pattern[] patterns = new Pattern[] { Pattern.compile(".com"), Pattern.compile("http://"), Pattern.compile("http://\\w+.com/") };
for (Pattern pattern : patterns) {
log.info("input[{}] pattern[{}]", input, pattern);
log.info("find() result is {}", pattern.matcher(input).find());
log.info("lookingAt() result is {}", pattern.matcher(input).lookingAt());
log.info("matches() result is {}\n", pattern.matcher(input).matches());
}
input[http://example.com/] pattern[.com]
find() result is true
lookingAt() result is false
matches() result is false
input[http://example.com/] pattern[http://]
find() result is true
lookingAt() result is true
matches() result is false
input[http://example.com/] pattern[http://\w+.com/]
find() result is true
lookingAt() result is true
matches() result is true
抽出
Matcher#group()メソッドでマッチした文字列を取得できる。
String input = "cat dog cap";
Pattern pattern = Pattern.compile("ca.");
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
String matched = matcher.group();
System.out.printf("[%s] がマッチしました。 Pattern:[%s] input:[%s]\n", matched, pattern, input);
}
[cat] が抽出されました。
[cap] が抽出されました。
置換
次の2つのメソッドが用意されている。置換された文字列が戻り値。
メソッド | 概要 |
---|---|
replaceFirst() |
最初の部分シーケンスを指定された置換文字列に置き換える。 |
replaceAll() |
指定された置換文字列に置き換える。 |
String input = "---dog---dog---dog---";
Pattern pattern = Pattern.compile("dog");
String replacement = "cat";
log.info("input[{}] pattern[{}] replacement[{}]", input, pattern, replacement);
log.info("replaceFirst() replaced [{}]", pattern.matcher(input).replaceFirst(replacement));
log.info(" replaceAll() replaced [{}]", pattern.matcher(input).replaceAll(replacement));
input[---dog---dog---dog---] pattern[dog] replacement[cat]
replaceFirst() replaced [---cat---dog---dog---]
replaceAll() replaced [---cat---cat---cat---]
分割
Pattern#split()を使ってString配列に分割できる。
String input = "one-two-three";
Pattern pattern = Pattern.compile("-");
log.info("input[{}] pattern[{}]", input, pattern);
log.info("split() result is [{}]", Arrays.toString(pattern.split(input)));
input[one-two-three] pattern[-]
split() result is [[one, two, three]]
ユーティリティメソッドによる正規表現処理
正規表現処理で必ずしもPatternとMatcherを使う必要はない。Stringクラスを中心にの使いやすいユーティリティメソッドが用意されている。ただしPatternの使い回しや細かい処理は当然できないので、そういった場合はPatternとMatcherを使う。
メソッド | 対応するユーティリティメソッド |
---|---|
Matcher#matches() |
String#matches() or Pattern#matches() |
Matcher#replaceAll() |
String#replaceAll() |
Matcher#replaceFirst() |
String#replaceFirst() |
Pattern#split() |
String#split() |
実装としては内部でPatternやMatcherが使われているのがほとんど。
Appendix A: 参考
Appendix B: 改訂履歴
-
v1.0, 2013-09-18: 初稿