如何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这样的模板库。
这里是一个例子:
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