如何replaceJavastring中的一组令牌?

我有以下模板string: "Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]"

我也有stringvariables名称,发票号码和截止date – 什么是最好的方式来replace模板中的variables与variables?

(请注意,如果一个variables碰巧包含一个令牌,它不应该被replace)。


编辑

感谢@laginimaineb和@ alan-moore, 这里是我的解决scheme:

 public static String replaceTokens(String text, Map<String, String> replacements) { Pattern pattern = Pattern.compile("\\[(.+?)\\]"); Matcher matcher = pattern.matcher(text); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { String replacement = replacements.get(matcher.group(1)); if (replacement != null) { // matcher.appendReplacement(buffer, replacement); // see comment matcher.appendReplacement(buffer, ""); buffer.append(replacement); } } matcher.appendTail(buffer); return buffer.toString(); } 

最有效的方法是使用匹配器不断查找expression式并replace它们,然后将文本附加到string构build器:

 Pattern pattern = Pattern.compile("\\[(.+?)\\]"); Matcher matcher = pattern.matcher(text); HashMap<String,String> replacements = new HashMap<String,String>(); //populate the replacements map ... StringBuilder builder = new StringBuilder(); int i = 0; while (matcher.find()) { String replacement = replacements.get(matcher.group(1)); builder.append(text.substring(i, matcher.start())); if (replacement == null) builder.append(matcher.group(0)); else builder.append(replacement); i = matcher.end(); } builder.append(text.substring(i, text.length())); return builder.toString(); 

我真的不认为你需要使用模板引擎或类似的东西。 您可以使用String.format方法,如下所示:

 String template = "Hello %s Please find attached %s which is due on %s"; String message = String.format(template, name, invoiceNumber, dueDate); 

你可以尝试使用像Apache Velocity这样的模板库。

http://velocity.apache.org/

这里是一个例子:

 import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import java.io.StringWriter; public class TemplateExample { public static void main(String args[]) throws Exception { Velocity.init(); VelocityContext context = new VelocityContext(); context.put("name", "Mark"); context.put("invoiceNumber", "42123"); context.put("dueDate", "June 6, 2009"); String template = "Hello $name. Please find attached invoice" + " $invoiceNumber which is due on $dueDate."; StringWriter writer = new StringWriter(); Velocity.evaluate(context, writer, "TemplateName", template); System.out.println(writer); } } 

输出将是:

 马克,你好。 请参阅2009年6月6日到期的附加发票42123。 

不幸的是,上面提到的舒适的方法String.format只能从Java 1.5开始(现在应该是相当标准的,但你永远不知道)。 相反,你也可以使用Java的类MessageFormat来replace占位符。

它支持“{number}”forms的占位符,所以你的消息看起来像“Hello {0}”,请在{2}处find附加的{1}。 这些string可以很容易地使用ResourceBundles进行外部化(例如用于具有多个语言环境的本地化)。 replace可以使用MessageFormat类的static'format方法来完成:

 String msg = "Hello {0} Please find attached {1} which is due on {2}"; String[] values = { "John Doe", "invoice #123", "2009-06-30" }; System.out.println(MessageFormat.format(msg, values)); 

您可以使用模板库进行复杂的模板replace。

FreeMarker是一个非常好的select。

http://freemarker.sourceforge.net/

但是对于简单的任务来说,还有一个简单的工具类可以帮助你。

org.apache.commons.lang3.text.StrSubstitutor

这是非常强大的,可定制的,易于使用。

这个类取一段文本,并replace其中的所有variables。 variables的默认定义是$ {variableName}。 前缀和后缀可以通过构造函数和设置方法来改变。

variables值通常从映射中parsing出来,但也可以从系统属性中parsing出来,或者通过提供一个自定义variablesparsing器来parsing。

例如,如果要将系统环境variablesreplace为模板string,则代码如下:

 public class SysEnvSubstitutor { public static final String replace(final String source) { StrSubstitutor strSubstitutor = new StrSubstitutor( new StrLookup<Object>() { @Override public String lookup(final String key) { return System.getenv(key); } }); return strSubstitutor.replace(source); } } 
 System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L)); 

输出:你好,join! 你有10条消息“

 String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date) 

这取决于您想要replace的实际数据的位置。 你可能有这样的地图:

 Map<String, String> values = new HashMap<String, String>(); 

包含所有可以replace的数据。 然后你可以迭代地图并改变string中的所有内容,如下所示:

 String s = "Your String with [Fields]"; for (Map.Entry<String, String> e : values.entrySet()) { s = s.replaceAll("\\[" + e.getKey() + "\\]", e.getValue()); } 

您也可以遍历string并查找地图中的元素。 但是这有点复杂,因为你需要parsing查找[]的string。 你可以用一个正则expression式来使用Pattern和Matcher。

我的解决scheme,以取代$ {variable}风格的标记(灵感来自这里和Spring UriTemplate的答案):

 public static String substituteVariables(String template, Map<String, String> variables) { Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}"); Matcher matcher = pattern.matcher(template); // StringBuilder cannot be used here because Matcher expects StringBuffer StringBuffer buffer = new StringBuffer(); while (matcher.find()) { if (variables.containsKey(matcher.group(1))) { String replacement = variables.get(matcher.group(1)); // quote to work properly with $ and {,} signs matcher.appendReplacement(buffer, replacement != null ? Matcher.quoteReplacement(replacement) : "null"); } } matcher.appendTail(buffer); return buffer.toString(); } 

在过去,我用StringTemplate和Groovy模板解决了这种问题。

最终,使用模板引擎的决定应该基于以下因素:

  • 你会在应用程序中有很多这些模板吗?
  • 你是否需要在不重新启动应用程序的情况下修改模板?
  • 谁将会维护这些模板? 参与该项目的Java程序员或业务分析师?
  • 您是否需要将逻辑放入模板中的能力,如基于variables值的条件文本?
  • 你是否需要能够在模板中包含其他模板?

如果上述任何一个适用于您的项目,我会考虑使用模板引擎,其中大部分提供此function,等等。

我用了

 String template = "Hello %s Please find attached %s which is due on %s"; String message = String.format(template, name, invoiceNumber, dueDate); 

使用Apache Commons Library,您可以简单地使用Stringutils.replaceEach :

 public static String replaceEach(String text, String[] searchList, String[] replacementList) 

从文档 :

replace另一个string中出现的所有string。

传递给此方法的空引用是空操作,或者如果有任何“searchstring”或“要replace的string”为空,则replace将被忽略。 这不会重复。 要重复replace,请调用重载的方法。

  StringUtils.replaceEach(null, *, *) = null StringUtils.replaceEach("", *, *) = "" StringUtils.replaceEach("aba", null, null) = "aba" StringUtils.replaceEach("aba", new String[0], null) = "aba" StringUtils.replaceEach("aba", null, new String[0]) = "aba" StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba" StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b" StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba" StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte" (example of how it does not repeat) StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte" 

FYI

在新的Kotlin语言中,您可以直接在源代码中使用“string模板”,任何第三方库或模板引擎都不需要进行variablesreplace。

这是语言本身的一个特点。

请参阅: https : //kotlinlang.org/docs/reference/basic-types.html#string-templates