Java 如何用 SimpleDateFormat 模式替换字符串中的占位符
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16436027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to replace a placeholder in a String with a SimpleDateFormat Pattern
提问by d0x
In a given String like this
在这样的给定字符串中
".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"
I need to replace a customer
and a yyyyMMdd
timestamp.
我需要替换一个customer
和一个yyyyMMdd
时间戳。
To replace the customer
placeholder, I could use the StrSubstitutor
from Apache Commons. But how to replace the SimpleDateFormat
? We are running in a Spring enviourment, so maybe Spring EL
is an option?
要替换customer
占位符,我可以使用StrSubstitutor
来自 Apache Commons 的。但是如何更换SimpleDateFormat
呢?我们在 Spring 环境中运行,所以也许Spring EL
是一种选择?
The markup for the placeholders is not fixed, it is ok if another library needs syntactical changes.
占位符的标记不是固定的,如果另一个库需要语法更改也没关系。
This small tests shows the problem:
这个小测试显示了问题:
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);
}
回答by NilsH
Why don't you use MessageFormat
instead?
你为什么不MessageFormat
改用?
String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date);
Or with String.format
String result = String.format(".../uploads/%1$s/%2$tY%2$tm%2$td/report.pdf", customer, date);
回答by Walery Strauch
As NilsH suggested MessageFormat is really nice for this purpose. To have named variables you can hide MessageFormat behind your class:
由于 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;
}
}
And you have to adjust your testcase:
你必须调整你的测试用例:
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);
}
I have removed generics and replace those with String. Also isPlaceholder
and getPlaceholderValue
is hardcoded and expect ${value}syntax.
我已经删除了泛型并将其替换为 String。而且isPlaceholder
andgetPlaceholderValue
是硬编码的并且期望${value}语法。
But this is just just the idea to solve your problem. To do this can use the methods from StrSubstitutor
(just use is or make FormattedStrSubstitutor extends StrSubstitutor
).
但这只是解决您的问题的想法。要做到这一点,可以使用来自StrSubstitutor
(只需使用 is 或 make FormattedStrSubstitutor extends StrSubstitutor
)的方法。
Also you can use for example $d{value}for date formatting and $foo{value}for foo formatting.
您也可以使用例如$d{value}用于日期格式和$foo{value}用于 foo 格式。
UPDATE
更新
Could not sleep without full solution. You can add this method to FormattedStrSubstitutor
class:
没有完整的解决方案就无法入睡。您可以将此方法添加到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;
}
Your testcase is like in your question (small changes in placeholder):
你的测试用例就像你的问题(占位符的小变化):
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);
}
Same limitation as before; no generics and fix prefix and suffix for placeholder.
与以前相同的限制;没有泛型并修复占位符的前缀和后缀。
回答by anydoby
Looks like it's as simple as this?
看起来就这么简单?
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();
}