Java 中的字符串替换,类似于速度模板

在 Java 中是否有任何 String替换机制,可以用文本传递对象,并在发生时替换字符串。
例如,文本如下:

Hello ${user.name},
Welcome to ${site.name}.

我有的对象是 "user""site"。我想用来自对象的等效值替换 ${}中给出的字符串。这和我们在速度模板中替换物体是一样的。

167215 次浏览

这里有一个关于如何做到这一点的大纲。将其实现为实际代码应该相对简单。

  1. 创建模板中引用的所有对象的映射。
  2. 使用正则表达式在模板中查找变量引用并用它们的值替换它们(参见步骤3)。Matcher类将在查找和替换中派上用场。
  3. 将变量名拆分为点号。user.name会变成 username。在映射中查找 user以获取对象,并使用 反思从对象获取 name的值。假设您的对象具有标准的 getter,您将查找一个方法 getName并调用它。

看一下 java.text.MessageFormat类,MessageFormat 获取一组对象,对它们进行格式化,然后在适当的位置将格式化后的字符串插入到模式中。

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);

我对此进行了一个小型的测试实现。基本思想是调用 format并传递格式化字符串、对象的映射以及它们在本地具有的名称。

产出如下:

我的狗叫 Fido 是 Jane Doe 的。

public class StringFormatter {


private static final String fieldStart = "\\$\\{";
private static final String fieldEnd = "\\}";


private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
private static final Pattern pattern = Pattern.compile(regex);


public static String format(String format, Map<String, Object> objects) {
Matcher m = pattern.matcher(format);
String result = format;
while (m.find()) {
String[] found = m.group(1).split("\\.");
Object o = objects.get(found[0]);
Field f = o.getClass().getField(found[1]);
String newVal = f.get(o).toString();
result = result.replaceFirst(regex, newVal);
}
return result;
}


static class Dog {
public String name;
public String owner;
public String gender;
}


public static void main(String[] args) {
Dog d = new Dog();
d.name = "fido";
d.owner = "Jane Doe";
d.gender = "him";
Map<String, Object> map = new HashMap<String, Object>();
map.put("d", d);
System.out.println(
StringFormatter.format(
"My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.",
map));
}
}

注意: 由于未处理的异常,这不能编译。但是它使代码更容易阅读。

另外,我不喜欢在代码中自己构造映射,但是我不知道如何以编程方式获得本地变量的名称。最好的方法是,记住在你创建对象的时候就把它放到地图中。

下面的示例生成您希望从示例中得到的结果:

public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
Site site = new Site();
map.put("site", site);
site.name = "StackOverflow.com";
User user = new User();
map.put("user", user);
user.name = "jjnguy";
System.out.println(
format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

我还应该提到,我不知道 Velocity 是什么,所以我希望这个答案是相关的。

没有任何东西可以和速度相提并论因为速度就是用来解决这个问题的。您可以尝试的最接近的方法是查看 Formatter

Http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/formatter.html

然而据我所知,这个格式化程序是为了在 Java 中提供类似 C 语言的格式化选项而创建的,所以它可能不会完全满足您的需求,但是欢迎您尝试:)。

使用 Apache Commons Text 中的 StringSubstitutor

Https://commons.apache.org/proper/commons-text/

它将为您完成这项工作(以及它的开源... ...)

 Map<String, String> valuesMap = new HashMap<String, String>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);

有一些表达式语言实现可以帮助您完成这些任务,当需求增长时,使用您自己的实现可能比使用您自己的实现更好,例如 JUELMVEL

我喜欢并且已经成功地在至少一个项目中使用了 MVEL。

还可以参见 Stackflow 文章 非 JSP (独立)上下文中的 JSTL/JSP EL (表达式语言)

我的首选方法是 String.format(),因为它是一个一线程,不需要第三方库:

String message = String.format("Hello! My name is %s, I'm %s.", name, age);

我经常使用这种方法,例如在异常消息中使用:

throw new Exception(String.format("Unable to login with email: %s", email));

提示: 您可以放入任意多的变量,因为 format()使用 瓦拉格

我在 java 中使用 Groovy Shell 来解析带有 Groovy GString 的模板:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);

我创建了这个使用香草 Java 的实用程序。它结合了两种格式... ... 来自 String.format 的 {}%s样式... ..。变成一个方法调用。请注意,它只替换空的 {}括号,而不是 {someWord}

public class LogUtils {


public static String populate(String log, Object... objects) {
log = log.replaceAll("\\{\\}", "%s");
return String.format(log, objects);
}


public static void main(String[] args) {
System.out.println(populate("x = %s, y ={}", 5, 4));;
}


}

就具有其他服务器端模板特性的类 Velocity 语法而言,Handlebars.java 可能是一个更好的选择。

Http://jknack.github.io/handlebars.java/

Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello \{\{this}}!");
System.out.println(template.apply("Handlebars.java"));

从 Java15开始,就有了 String.formatted()方法(参见 文件)。

str.formatted(args)相当于 String.format(str, args),没有那么多的仪式。

对于问题中提到的例子,可以采用以下方法:

"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())