読者です 読者をやめる 読者になる 読者になる

java.util.regex.Matcher とリスト置換

テンプレートのような、ある文字列の特定の文字をパラメータ文字列リストに置き換える処理は簡単だと思ってたが
以外と難しい。java.util.regex.Matcher を回した時に、置換メソッド実行していけば良いと思ってたが、
Matcher に、replaceFirst か replaceAll しかないではないか。

お題:

String str = "123456?789?01234?5";
String[] parameters = { "A", "B", "'c'" };

とあった時、'?' の文字をこの parameters の文字列に順に置換して

123456A789B01234'c'5

としたいのである。

'?' でテンプレートにあたる文字列 str を split してなんてやり方は、なんか賢くない。。
Matcher を使うことにして考えて書いたら、なんか動物的な思考のコーディングだけど以下のようなった。

Matcher m = Pattern.compile("\\?").matcher(str);
List<Integer> ixlist = new ArrayList<>();
while(m.find()) ixlist.add(m.start());
Collections.reverse(ixlist);

AtomicReference<String> cache = new AtomicReference<String>(str);
AtomicInteger n = new AtomicInteger(parameters.length-1);
ixlist.stream().forEach(i->{
   cache.set(cache.get().substring(0, i) + parameters[n.get()] + cache.get().substring(i+1));
   n.set(n.get()-1);
});

String result = cache.get();

これで、求めてる結果を得ることができる。
Matcher の find() 後の start() の結果を逆順リストにして String#substring で文字列を作り直してる
→ なんか感情を丸出しのコードだ。

この題目を解く必要性を打ち明けると mybatis のログ、org.apache.ibatis.logging.jdbc.BaseJdbcLogger 
が出力する SQL
Preparing と Parameters から、動かせるSQL文をリメイクしたかったからだ。