2015年6月1日月曜日

Javaの正規表現で後方参照を使用する

テキスト処理で重要になる正規表現と後方参照。
Javaで実装するサンプルを2つ紹介します。

$nを使用する方法
Matcher#replaceAllメソッドや、Matcher#replaceFirstメソッドは$nで後方参照を使用できます。
String regex = "\\[([0-9]+)\\]";
String src = "[1] [2] [3] [4] [5]";
 
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(src);
String  result1 = matcher.replaceAll("($1)");
System.out.println(result1);
// => (1) (2) (3) (4) (5)


Matcher#groupを使用する方法
Matcher#groupメソッドを使用する方法は多少複雑です。
正規表現にマッチする部分は、Matcher#startメソッドとMatcher#endから取得できます。
この部分文字列を置き換えてしまえばいいというわけです。
こちらの方法では、後方参照で取得した文字列を元にして、編集を加えられるというメリットがあります。
サンプルではアラビア数字から漢数字へ置き換えています。
String regex = "\\[([0-9]+)\\]";
String src = "[1] [2] [3] [4] [5]";
String[] kan = {"一", "ニ", "三", "四", "五"};
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(src);
StringBuilder result2 = new StringBuilder();
int lastEnd = 0;
String outOfMatch = "";
while(matcher.find()) {
    outOfMatch = src.substring(lastEnd, matcher.start());
    String group = matcher.group(1);
    int n = Integer.parseInt(group);
    String kanN = kan[n-1];
    result2.append(outOfMatch);
    result2.append("(" + kanN + ")");
    lastEnd = matcher.end();
}
outOfMatch = src.substring(lastEnd);
result2.append(outOfMatch);
System.out.println(result2);
// => (一) (ニ) (三) (四) (五)

以下、サンプルソース全体です。



import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Program {

    public static void main(String[] args) {
 // 正規表現の後方参照の使い方を紹介するプログラム
 // []に囲まれた数字を()に囲まれた数字に置換し、画面へ出力する
 // 1. $nを使う方式
 //    - Pattern#matcherを呼び、Matcherオブジェクトを得る
 //    - Matcher#replaceAllの引数として$1を与えて置換する
 // 2. groupを使う方式
 //    - Pattern#matcherを呼び、Matcherオブジェクトを得る
 //    - Matcher#findを条件としてループする
 //    - 前回のMatcher#endからMatcher#startを結果文字列へ追加する
 //    - Matcher#group(1)を漢数字へ変換し、()で囲み、結果文字列へ追加する
 //    - 末尾の文字列を追加する
 String regex = "\\[([0-9]+)\\]";
 String src = "[1] [2] [3] [4] [5]";
 String[] kan = {"一", "ニ", "三", "四", "五"};
 
 Pattern pattern = Pattern.compile(regex);
 Matcher matcher = pattern.matcher(src);

 String  result1 = matcher.replaceAll("($1)");
 System.out.println(result1);

 matcher.reset();

 StringBuilder result2 = new StringBuilder();
 int lastEnd = 0;
 String outOfMatch = "";
 while(matcher.find()) {
     outOfMatch = src.substring(lastEnd, matcher.start());
     String group = matcher.group(1);
     int n = Integer.parseInt(group);
     String kanN = kan[n-1];
     result2.append(outOfMatch);
     result2.append("(" + kanN + ")");
     lastEnd = matcher.end();
 }
 outOfMatch = src.substring(lastEnd);
 result2.append(outOfMatch);
 System.out.println(result2);
    }
}

参考
Matcher#replaceAll、String#replaceAllで後方参照が使える
Matcher (Java Platform SE 7 ) - Oracle Documentation
Pattern (Java Platform SE 7 ) - Oracle Documentation

0 件のコメント:

コメントを投稿