在像这样的给定字符串中
".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"
我需要替换customer
和yyyyMMdd
时间戳。
要替换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);
}
答案 0 :(得分:28)
为什么不使用MessageFormat
?
String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date);
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替换了。 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);
}
与以前相同的限制;没有泛型并修复了占位符的前缀和后缀。
答案 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();
}