如何使用SimpleDateFormat模式替换String中的占位符

时间:2013-05-08 08:33:18

标签: java apache-commons spring-el

在像这样的给定字符串中

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

我需要替换customeryyyyMMdd时间戳。

要替换customer占位符,我可以使用Apache Commons中的StrSubstitutor。但是如何替换SimpleDateFormat?我们在Spring环境中运行,所以也许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);
}

3 个答案:

答案 0 :(得分:28)

为什么不使用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);

答案 1 :(得分:9)

正如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替换了。 isPlaceholdergetPlaceholderValue也是硬编码的,并且期望 $ {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);
}

与以前相同的限制;没有泛型并修复了占位符的前缀和后缀。

答案 2 :(得分:0)

看起来像这一样简单吗?

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();
}