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

Joe*_*Joe 83 java string reflection velocity

StringJava中是否有任何替换机制,我可以使用文本传递对象,并在发生时替换字符串.
例如,文本是:

Hello ${user.name},
    Welcome to ${site.name}. 
Run Code Online (Sandbox Code Playgroud)

我拥有的对象是"user""site".我想${}用对象中的等价值替换内部给出的字符串.这与我们替换速度模板中的对象相同.

JH.*_*JH. 127

使用apache commons lang.

https://commons.apache.org/proper/commons-lang/

它会为你(及其开源......)做到这一点

 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);
Run Code Online (Sandbox Code Playgroud)

  • `StrSubstitutor`从1.3开始弃用,改为使用`StringSubstitutor`.此类将在2.0中删除.导入`StringSubstitutor`的Gradle依赖是`org.apache.commons:commons-text:1.4` (6认同)
  • 用于StrSubstitutor的Javadoc http://commons.apache.org/lang/api-release/org/apache/commons/lang/text/StrSubstitutor.html (3认同)
  • `StrSubstitutor`现已在[https://commons.apache.org/proper/commons-lang/](https://commons.apache.org/proper/commons-lang/)中弃用.用户[https://commons.apache.org/proper/commons-text/](https://commons.apache.org/proper/commons-text/)代替 (3认同)

Rea*_*wTo 119

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

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

  • 谢谢!我知道java应该有一个内置的方式来做到这一点,而不必使用怪异的模板引擎做这么简单的事情! (9认同)
  • +1。请注意,`format`还带有`Object ...`可变参数,因此您可以在更喜欢`format(“ {0} world {1}”,“ Hello”,“!”);的地方使用这种更简洁的语法。 (4认同)
  • 似乎 String.format 可以做任何可以做的事情——/sf/ask/196674341/ (2认同)

jjn*_*guy 19

我把这个小测试实现了.基本思想是调用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

另外,我不喜欢你必须自己在代码中构建地图,但我不知道如何以编程方式获取局部变量的名称.最好的方法是记住在创建对象后立即将对象放入地图中.

以下示例生成您希望从示例中获得的结果:

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));
}
Run Code Online (Sandbox Code Playgroud)

我还要提一下,我不知道Velocity是什么,所以我希望这个答案是相关的.

  • @Joe,很高兴我可以帮忙.这是一个很好的借口让我最终练习编写一些在Java中使用反射的代码. (2认同)

art*_*ohe 13

我的首选方式是String.format()因为它是一个一体的,并且不需要第三方库:

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

我经常使用它,例如在异常消息中:

throw new Exception(String.format("Unable to login with email: %s", email));
Run Code Online (Sandbox Code Playgroud)

提示:您可以输入任意多个变量,因为format()使用了Varargs

  • @asherbar,您可以在格式字符串中使用参数索引说明符,例如 `String.format("Hello!我的名字是 %1$s,我是 %2$s。您问为什么我的名字是 %1$s?好吧我只有 %2$s 岁,所以我不知道“、姓名、年龄)` (10认同)
  • 当您需要多次重复相同的论点时,这不太有用。例如: `String.format("你好!我的名字是 %s,我是 %s。你为什么问我的名字是 %s?好吧,我只有 %s 岁,所以我不知道",name,年龄,姓名,年龄);`。这里的其他答案要求每个参数仅指定一次。 (6认同)
  • @jazzpi 我从来不知道这一点。谢谢! (4认同)

Mah*_*zad 6

Java 现在有字符串模板(从版本21开始,作为预览功能)。

请参阅此处的字符串模板提案 (JEP 430)

大致是这样的:

String name = "John";
String info = STR."I am \{name}";
System.out.println(info); // I am John
Run Code Online (Sandbox Code Playgroud)

PS Kotlin与 Java 100% 互操作。它支持开箱即用的更清晰的字符串模板:

val name = "John"
val info = "I am $name"
println(info) // I am John
Run Code Online (Sandbox Code Playgroud)

扩展功能相结合,您可以实现与 Java 模板处理器(例如STR)相同的功能。


cas*_*nca 5

这是你如何做到这一点的概述.将其实现为实际代码应该相对简单.

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


Chr*_*oop 5

有几种表达式语言实现可以为您执行此操作,可能比使用您自己的实现更可取,或者如果您的需求增长,请参见例如JUELMVEL

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

另请参阅非 JSP(独立)上下文中的 Stackflow 帖子JSTL/JSP EL(表达式语言)


Ahm*_*wan 5

从 Java 15 开始,您就有了该方法String.formatted()(请参阅文档)。

str.formatted(args)相当于String.format(str, args)少了一些仪式。

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

"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())
Run Code Online (Sandbox Code Playgroud)