web-dev-qa-db-ja.com

文字列のプレースホルダーをSimpleDateFormatパターンで置き換える方法

このような与えられた文字列で

".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"

customeryyyyMMddのタイムスタンプを置き換える必要があります。

customerプレースホルダーを置き換えるには、Apache CommonsのStrSubstitutorを使用できます。しかし、SimpleDateFormatを置き換える方法は?私たちは春の環境で走っているので、たぶんSpring ELはオプションですか?

プレースホルダーのマークアップは固定されていません。別のライブラリが構文の変更を必要とする場合は問題ありません。

この小さなテストは問題を示しています:

SimpleDateFormat            formatter   = new SimpleDateFormat("yyyyMMdd");

String                      template    = ".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf";

@Test
public void shouldResolvePlaceholder()
{
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");

    final String filledTemplate = StrSubstitutor.replace(this.template, model);

    assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate);
}
11
d0x

代わりに MessageFormat を使用しないのはなぜですか?

String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date);

または String.format

String result = String.format(".../uploads/%1$s/%2$tY%2$tm%2$td/report.pdf", customer, date);
29
NilsH

NilsHが提案したように、MessageFormatはこの目的にとって本当に素晴らしいものです。名前付き変数を使用するには、クラスの背後にMessageFormatを隠すことができます。

public class FormattedStrSubstitutor {
    public static String formatReplace(Object source, Map<String, String> valueMap) {
        for (Map.Entry<String, String> entry : valueMap.entrySet()) {   
            String val = entry.getValue();
            if (isPlaceholder(val)) {
                val = getPlaceholderValue(val);
                String newValue = reformat(val);

                entry.setValue(newValue);
            }
        }

        return new StrSubstitutor(valueMap).replace(source);
    }

    private static boolean isPlaceholder(String isPlaceholder) {
        return isPlaceholder.startsWith("${");
    }

    private static String getPlaceholderValue(String val) {
        return val.substring(2, val.length()-1);
    }

    private static String reformat(String format) {
        String result = MessageFormat.format("{0,date," + format + "}", new Date());

        return result;
    }
}

そして、あなたはあなたのテストケースを調整する必要があります:

SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");

String template = ".../uploads/${customer}/${dateTime}/report.pdf";

@Test
public void shouldResolvePlaceholder() {
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");
    model.put("dateTime", "${yyyyMMdd}");

    final String filledTemplate = FormattedStrSubstitutor.formatReplace(this.template,
        model);

    assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
        + "/report.pdf", filledTemplate);
}

ジェネリックを削除し、Stringに置き換えました。また、isPlaceholderおよびgetPlaceholderValueはハードコーディングされており、$ {value}構文を期待しています。

ただし、これは問題を解決するためのアイデアにすぎません。これを行うには、StrSubstitutorのメソッドを使用できます(isまたはmake FormattedStrSubstitutor extends StrSubstitutorを使用するだけです)。

また、たとえば、$ d {value}を日付の書式設定に使用し、$ foo {value}fooフォーマット用。

[〜#〜]更新[〜#〜]

完全な解決策なしでは眠れませんでした。このメソッドをFormattedStrSubstitutorクラスに追加できます:

public static String replace(Object source,
        Map<String, String> valueMap) {

    String staticResolved = new StrSubstitutor(valueMap).replace(source);

    Pattern p = Pattern.compile("(\\$\\{date)(.*?)(\\})");
    Matcher m = p.matcher(staticResolved);

    String dynamicResolved = staticResolved;
    while (m.find()) {
        String result = MessageFormat.format("{0,date" + m.group(2) + "}",
                new Date());

        dynamicResolved = dynamicResolved.replace(m.group(), result);
    }

    return dynamicResolved;
}

あなたのテストケースはあなたの質問のようです(プレースホルダーの小さな変更):

SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");

String template = ".../uploads/${customer}/${date,yyyyMMdd}/report.pdf";

@Test
public void shouldResolvePlaceholder() {
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");

    final String filledTemplate =  FormattedStrSubstitutor.replace(this.template,
            model);

    assertEquals(
            ".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
                    + "/report.pdf", filledTemplate);
}

以前と同じ制限。ジェネリックはなく、プレースホルダーのプレフィックスとサフィックスを修正しました。

9
Walery Strauch

こんなに簡単なの?

static final Pattern DOLLARS = Pattern.compile("\\$\\{([^}]+)}");

public static String resolve(String string, Map<String,String> config) {
    StringBuilder builder = new StringBuilder();
    Matcher matcher = DOLLARS.matcher(string);
    int start = 0;
    while (matcher.find(start)) {
        builder.append(string.substring(start, matcher.start()));
        String property = matcher.group(1);
        String value = config.get(property);
        builder.append(value);
        start = matcher.end();
    }
    builder.append(string.substring(start));
    return builder.toString();
}
0
anydoby