如何将字符串中的占位符替换为简单日期格式模式

2022-09-05 00:15:38

在像这样的给定字符串中

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

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

为了替换占位符,我可以使用Apache Commons中的。但是如何更换?我们在春天的羡慕中奔跑,所以也许这是一种选择?customerStrSubstitutorSimpleDateFormatSpring 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);
}

答案 1

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

答案 2

正如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);
}

我已经删除了泛型并用字符串替换它们。也是硬编码的,并且期望 ${value} 语法。isPlaceholdergetPlaceholderValue

但这只是解决你问题的想法。要做到这一点,可以使用来自(只是使用是或使)的方法。StrSubstitutorFormattedStrSubstitutor 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);
}

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


推荐