给出一个像这样的字符串:
Hello {FIRST_NAME}, this is a personalized message for you.
FIRST_NAME是一个任意标记(传递给方法的地图中的一个键),编写一个将该字符串转换为的例程:
Hello Jim, this is a personalized message for you.
给出带有FIRST_NAME条目的地图 - >吉姆。
似乎StringTokenizer是最直接的方法,但Javadocs真的说你应该更喜欢使用正则表达式aproach。你会如何在基于正则表达式的解决方案中做到这一点?
答案 0 :(得分:11)
谢谢大家的答案!
Gizmo的答案绝对是开箱即用的,也是一个很好的解决方案,但遗憾的是不适合,因为格式不能仅限于Formatter类在这种情况下的作用。
Adam Paynter真正了解问题的核心,并采用正确的模式。
彼得·尼克斯和肖恩·布莱特有一个很好的解决办法,以避免正则表达式的所有复杂性,但如果有不好的令牌,我需要提出一些错误,这是不行的。但是就完成正则表达式和合理的替换循环而言,这是我提出的答案(谷歌和现有答案的一些帮助,包括Sean Bright关于如何使用group(1)vs的评论组()):
private static Pattern tokenPattern = Pattern.compile("\\{([^}]*)\\}");
public static String process(String template, Map<String, Object> params) {
StringBuffer sb = new StringBuffer();
Matcher myMatcher = tokenPattern.matcher(template);
while (myMatcher.find()) {
String field = myMatcher.group(1);
myMatcher.appendReplacement(sb, "");
sb.append(doParameter(field, params));
}
myMatcher.appendTail(sb);
return sb.toString();
}
doParameter从地图中获取值并将其转换为字符串,如果不存在则抛出异常。
另请注意,我更改了模式以查找空括号(即{}),因为这是显式检查的错误条件。
编辑:请注意,appendReplacement与字符串的内容无关。根据javadoc,它将$和反斜杠识别为一个特殊字符,因此我添加了一些转义来处理上面的示例。没有以最具表现意识的方式完成,但在我的情况下,值得尝试微量优化弦乐创作并不是一件足够大的事情。
感谢Alan M的评论,可以更简单地避免appendReplacement的特殊字符问题。
答案 1 :(得分:8)
好吧,我宁愿使用String.format(),也不想使用MessageFormat。
答案 2 :(得分:6)
String.replaceAll("{FIRST_NAME}", actualName);
查看javadocs here。
答案 3 :(得分:4)
试试这个:
注意: author's final solution基于此示例构建,更加简洁。
public class TokenReplacer {
private Pattern tokenPattern;
public TokenReplacer() {
tokenPattern = Pattern.compile("\\{([^}]+)\\}");
}
public String replaceTokens(String text, Map<String, String> valuesByKey) {
StringBuilder output = new StringBuilder();
Matcher tokenMatcher = tokenPattern.matcher(text);
int cursor = 0;
while (tokenMatcher.find()) {
// A token is defined as a sequence of the format "{...}".
// A key is defined as the content between the brackets.
int tokenStart = tokenMatcher.start();
int tokenEnd = tokenMatcher.end();
int keyStart = tokenMatcher.start(1);
int keyEnd = tokenMatcher.end(1);
output.append(text.substring(cursor, tokenStart));
String token = text.substring(tokenStart, tokenEnd);
String key = text.substring(keyStart, keyEnd);
if (valuesByKey.containsKey(key)) {
String value = valuesByKey.get(key);
output.append(value);
} else {
output.append(token);
}
cursor = tokenEnd;
}
output.append(text.substring(cursor));
return output.toString();
}
}
答案 4 :(得分:3)
使用import java.util.regex。*:
Pattern p = Pattern.compile("{([^{}]*)}");
Matcher m = p.matcher(line); // line being "Hello, {FIRST_NAME}..."
while (m.find) {
String key = m.group(1);
if (map.containsKey(key)) {
String value= map.get(key);
m.replaceFirst(value);
}
}
因此,建议使用正则表达式,因为它可以轻松识别字符串中需要替换的位置,以及提取替换键的名称。它比打破整个字符串更有效率。
您可能希望循环使用内部的Matcher线和外部的Pattern线,这样您就可以替换所有线。该模式永远不需要重新编译,并且避免不必要地这样做更有效。
答案 5 :(得分:2)
最直接的看法似乎就是这样:
public static void main(String[] args) {
String tokenString = "Hello {FIRST_NAME}, this is a personalized message for you.";
Map<String, String> tokenMap = new HashMap<String, String>();
tokenMap.put("{FIRST_NAME}", "Jim");
String transformedString = tokenString;
for (String token : tokenMap.keySet()) {
transformedString = transformedString.replace(token, tokenMap.get(token));
}
System.out.println("New String: " + transformedString);
}
它循环遍历所有标记并用您需要的内容替换每个标记,并使用标准的String方法进行替换,从而跳过整个RegEx挫折。
答案 6 :(得分:2)
根据字符串的复杂程度,您可以尝试使用更严格的字符串模板语言,如Velocity。在Velocity的案例中,你会做这样的事情:
Velocity.init();
VelocityContext context = new VelocityContext();
context.put( "name", "Bob" );
StringWriter output = new StringWriter();
Velocity.evaluate( context, output, "",
"Hello, #name, this is a personalized message for you.");
System.out.println(output.toString());
但如果您只想替换一个或两个值,那么这可能是过度的。
答案 7 :(得分:1)
import java.util.HashMap;
public class ReplaceTest {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("FIRST_NAME", "Jim");
map.put("LAST_NAME", "Johnson");
map.put("PHONE", "410-555-1212");
String s = "Hello {FIRST_NAME} {LAST_NAME}, this is a personalized message for you.";
for (String key : map.keySet()) {
s = s.replaceAll("\\{" + key + "\\}", map.get(key));
}
System.out.println(s);
}
}
答案 8 :(得分:0)
文档意味着您应该更喜欢编写基于正则表达式的标记生成器IIRC。对您来说可能更有效的是标准的正则表达式搜索替换。
答案 9 :(得分:0)
通常我们在这种情况下使用MessageFormat,同时从ResourceBundle加载实际的消息文本。这为您提供了G10N友好的额外好处。