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

发布于 2025-01-10 19:52:19 字数 341 浏览 0 评论 0原文

Java 中是否有任何 String 替换机制,我可以在其中传递带有文本的对象,并在字符串出现时替换它? 例如,文本是:

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

我拥有的对象是 usersite。我想用对象中的等效值替换 ${} 中给出的字符串。这与我们替换 velocity 模板中的对象相同。

Is there any String replacement mechanism in Java, where I can pass objects with a text, and it replaces the string as it occurs?
For example, the text is:

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

The objects I have are user and site. I want to replace the strings given inside ${} with its equivalent values from the objects. This is same as we replace objects in a velocity template.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

情话墙 2025-01-17 19:52:19

使用 Apache Commons Text 中的 StringSubstitutor

依赖项

导入 使用 maven 导入 Apache commons 文本依赖项,如下所示:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.10.0</version>
</dependency>

示例

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);

Use StringSubstitutor from Apache Commons Text.

Dependency import

Import the Apache commons text dependency using maven as bellow:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-text</artifactId>
    <version>1.10.0</version>
</dependency>

Example

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);
她说她爱他 2025-01-17 19:52:19

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

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

Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, then inserts the formatted strings into the pattern at the appropriate places.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
椵侞 2025-01-17 19:52:19

我的首选方法是 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() 使用 Varargs

My preferred way is String.format() because its a oneliner and doesn't require third party libraries:

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

I use this regularly, e.g. in exception messages like:

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

Hint: You can put in as many variables as you like because format() uses Varargs

陪你到最终 2025-01-17 19:52: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));
    }
}

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

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

以下示例生成您想要的示例结果:

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 是什么,所以我希望这个答案是相关的。

I threw together a small test implementation of this. The basic idea is to call format and pass in the format string, and a map of objects, and the names that they have locally.

The output of the following is:

My dog is named fido, and Jane Doe owns him.

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));
    }
}

Note: This doesn't compile due to unhandled exceptions. But it makes the code much easier to read.

Also, I don't like that you have to construct the map yourself in the code, but I don't know how to get the names of the local variables programatically. The best way to do it, is to remember to put the object in the map as soon as you create it.

The following example produces the results that you want from your example:

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));
}

I should also mention that I have no idea what Velocity is, so I hope this answer is relevant.

时光与爱终年不遇 2025-01-17 19:52:19

以下概述了如何执行此操作。将其实现为实际代码应该相对简单。

  1. 创建将在模板中引用的所有对象的映射。
  2. 使用正则表达式在模板中查找变量引用并将其替换为其值(请参阅步骤 3)。 Matcher 类将会出现方便查找和替换。
  3. 在点处分割变量名称。 user.name 将变为 username。在地图中查找 user 以获取对象并使用 反射从对象中获取name的值。假设您的对象具有标准 getter,您将查找方法 getName 并调用它。

Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.

  1. Create a map of all the objects that will be referenced in the template.
  2. Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
  3. Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.
南七夏 2025-01-17 19:52:19

Java 21 引入了字符串模板作为预览功能。
Java 23 撤回/删除了该功能。

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

大致是这样的:

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

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

val name = "John"
val info = "I am $name"
println(info) // I am John

结合扩展函数,您可以实现相同的效果Java 模板处理器(例如STR)将执行的操作。

Java 21 introduced string templates as a preview feature.
Java 23 withdrew/removed the feature.

See the string templates proposal (JEP 430) here.

It was something along the lines of this:

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

P.S. Kotlin is 100% interoperable with Java. It supports cleaner string templates out of the box:

val name = "John"
val info = "I am $name"
println(info) // I am John

Combined with extension functions, you can achieve the same thing the Java template processors (e.g. STR) will do.

携君以终年 2025-01-17 19:52:19

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

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

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

There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL

I like and have successfully used MVEL in at least one project.

Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context

烂柯人 2025-01-17 19:52:19

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

str.formatted(args) 相当于 String.format(str, args),但仪式较少。

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

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

Since Java 15 you have the method String.formatted() (see documentation).

str.formatted(args) is the equivalent of String.format(str, args) with less ceremony.

For the example mentioned in the question, the method could be used as follows:

"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())
友谊不毕业 2025-01-17 19:52:19

就类似 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"));

Handlebars.java might be a better option in terms of a Velocity-like syntax with other server-side templating features.

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

Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));
沫雨熙 2025-01-17 19:52:19

我在java中使用GroovyShell用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);

I use GroovyShell in java to parse template with 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);
眼前雾蒙蒙 2025-01-17 19:52:19

我创建了这个使用普通 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));;
    }

}

I created this utility that uses vanilla Java. It combines two formats... {} and %s style from String.format.... into one method call. Please note it only replaces empty {} brackets, not {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));;
    }

}
绝情姑娘 2025-01-17 19:52:19

没有任何现成的东西可以与速度相媲美,因为速度是为了解决这个问题而编写的。您可以尝试的最接近的方法是查看格式化程序

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

然而格式化程序我知道它的创建是为了在 Java 中提供类似 C 的格式化选项,因此它可能无法完全满足您的需求,但欢迎您尝试:)。

There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter

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

However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文