12

在这样的给定字符串中

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

我需要替换一个customer和一个yyyyMMdd时间戳。

要替换customer占位符,我可以使用StrSubstitutor来自 Apache Commons 的。但是如何更换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);
}
4

3 回答 3

31

你为什么不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);
于 2013-05-08T08:45:05.613 回答
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。而且isPlaceholderandgetPlaceholderValue是硬编码的并且期望${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);
}

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

于 2013-05-08T13:54:28.500 回答
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();
}
于 2018-06-13T13:01:59.730 回答