JavaでMapのキーなどから文字列をフォーマットする

{width=100, height=150, another=200}のようなMapがあるものとして、
"resultW{width}H{height}"→"resultW100H150"のように文字列のフォーマットを行う。
Propertiesクラスなどでも代用可能。
フォーマット文字列や各パラメータを外部ファイルで指定すれば、
String.formatと異なりソースを変えずに出力形式を変えられる*1
こういうやり方標準ライブラリにありそうな気はするけどとりあえず見つからなかったので。

以下ソース

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

public class FormatByParameterNames {
	public static void main(String[] args) {
		// 結果文字列に入れたいパラメータ
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put("width", "100");
		parameters.put("height", "150");
		parameters.put("another", "200");
		System.out.println("parameters: " + parameters);
		// 該当するパラメータの値を入れつつ以下のような形式で出力したい(出力形式を変えたくなったらここをいじる)
		// 最終的に"{文字列}"をparamters.get("文字列")へと変換して出力する
		String format = "resultW{width}H{height}.csv";
		System.out.println("format: " + format);

		// "{文字列}"に対してマッチしつつ、"文字列"部分を後方参照用に取っておくパターン
		Pattern pattern = Pattern.compile("\\{(\\w+)\\}");
		Matcher matcher = pattern.matcher(format);
		// 結果文字列をここに入れる
		StringBuilder sb = new StringBuilder();
		int lastEnd = 0;
		while (matcher.find()) {
			// 前回のマッチ部分との間にあるフォーマット文字列をそのまま結果文字列に追加
			sb.append(format.substring(lastEnd, matcher.start()));
			lastEnd = matcher.end();
			// パラメータのマップから、"文字列"という名前のキーを探してその値を結果文字列に追加
			sb.append(parameters.get(matcher.group(1)));
		}
		// 最終マッチ部分からフォーマットする文字列の終わりまで追加
		sb.append(format.substring(lastEnd));
		System.out.println("result: " + sb);
	}
}

結果

parameters: {another=200, height=150, width=100}
format: resultW{width}H{height}.csv
result: resultW100H150.csv

ついでにProperties用に関数化したものを置いておく

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

/**
 * プロパティの値によって文字列をフォーマットする
 * 
 * @author phithon
 * 
 */
public class ParameterFormatter {
    /** {\w+} → \w+ */
    private static final Pattern pattern = Pattern.compile("\\{(\\w+)\\}");

    /**
     * 文字列をプロパティ名によってフォーマットします。
     * 
     * @param format フォーマットする文字列
     * @param props プロパティ
     * @return プロパティの値によってフォーマットされた文字列
     * @throws IllegalArgumentException プロパティに含まれないキーワードがフォーマット文字列に含まれていた場合。
     */
    public static String formatByProperties(String format, Properties props) {
        Matcher matcher = pattern.matcher(format);
        StringBuilder sb = new StringBuilder();
        int lastEnd = 0;
        while (matcher.find()) {
            sb.append(format.substring(lastEnd, matcher.start()));
            lastEnd = matcher.end();
            String parameter = props.getProperty(matcher.group(1));
            if (parameter == null) {
                throw new IllegalArgumentException("parameter "
                        + matcher.group(1) + " not found.");
            }
            sb.append(parameter);
        }
        sb.append(format.substring(lastEnd));
        return sb.toString();
    }
}

*1:後から出力順を変えたりanotherを出力に加えたりする場合など