【问题标题】:How to Generate a String from a String Template in Java?如何从 Java 中的字符串模板生成字符串?
【发布时间】:2014-10-23 05:33:34
【问题描述】:

我希望我的 Java 应用程序从用户读取字符串,该字符串可能包含一些标签,例如:

String text = " value 1 = #value1 and value 2 = #value2 ";
int[] intArray = new int[] {4,5};

用户还将向应用程序输入一组值。作为一名程序员,我不知道字符串中值的确切数量。我想以编程方式生成这个字符串:

String result = " value 1 = 4 and value 2 = 5 "

为此,我实现了一种搜索#value* 正则表达式并将其替换为值堆栈中的第一个元素的方法。它循环直到程序在主字符串中找不到任何#value,问题是对于大文本,程序需要太多时间才能执行,考虑到采用的方法,这是正常的。

我还听说过一些使用 Velocity 和 FreeMarker 的模板技术,但我从未使用过它们(非常欢迎对此进行任何澄清)。

所以我的问题是:解决这个问题的最佳方法是什么(最短的执行时间)?

PS:我不需要代码,我只想要一个可以解决这个问题的方法或 API。

【问题讨论】:

  • 最短执行时间?你这是什么意思?另外,你看过 String.format() 吗?
  • pft... 某些字符串操作的最短执行时间 - 您要转换多少个字符串? 10?一万? 10mio?

标签: java regex string substring template-engine


【解决方案1】:

使用静态String.format(String format, Object... args) 方法以特定参数格式化您的字符串。

要了解有关如何正确创建有效模板字符串的更多详细信息,请参阅此文档: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html#detail

【讨论】:

  • 如上所述^_^
【解决方案2】:

如果您在每次替换时创建一个新的完整String,您确实会遇到问题。您可以尝试使用来自Matcher 的辅助方法来构建StringBuffer。对于大型输入,这应该更快:

String text = " value 1 = #value1 and value 2 = #value2 ";
int[] intArray = new int[] { 4, 5 };
Pattern p = Pattern.compile("#value(\\d+)");
Matcher m = p.matcher(text);
StringBuffer result = new StringBuffer();
while (m.find()) {
    m.appendReplacement(result, String.valueOf(intArray[Integer.parseInt(m.group(1)) - 1]));
}
m.appendTail(result);
System.out.println(result.toString());

编辑
许多人指出StringBuilder 更适合这份工作。我同意,但不幸的是 Matcher API 不接受 StringBuilder 作为 appendReplacement()appendTail() 方法的参数。

【讨论】:

  • 如果他担心最快的执行时间,那么StringBuilder 更快但缺乏线程安全性。
  • @Rudi:添加了一条评论来解决这个问题。你不是第一个指出这一点的人。 :)
  • 每天学习新东西。感谢您的澄清。
【解决方案3】:

有大量的模板/表达式语言引擎可以帮助你解决这个问题,VelocityFreemaker 也可以解决这个问题,但是对于这个相当简单的问题,它们可能太重了任务。

正如@Keppil (+1) 已经提到的,最简单的方法是使用 regexp。正确的代码将花费 O(n) 时间。

仅供参考,更复杂的情况可以查看Apache Jexl library。 Is 非常轻巧,并且具有清晰简单的 API。您的情况可以通过以下代码解决:

    JexlEngine jexl = new JexlEngine();
    Expression expression = jexl.createExpression("value 1 = #value1 value 2 = #value2");
    int[] values = {1, 2};
    JexlContext context = new MapContext();
    for (int i = 0; i <  values.length; i++) {
        context.set("#value" + (i + 1), values[i]);
    }
    String result = (String)expression.evaluate(context);

【讨论】:

  • freemarker vs velocity vs Stringtemplate 哪个更好?
  • 很难说,它们都是很好的库,这实际上取决于使用模式以及您对 API/功能集的满意程度。如果您需要 html/xml 处理,那么我建议您也看看 Thymeleaf。非常适合 HTML/XML(网页/丰富的电子邮件)模板处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 2012-03-13
  • 2016-02-22
  • 1970-01-01
相关资源
最近更新 更多