Replacing strings in java, similar to speed pattern

Is there any mechanism for replacing String in Java, where I can pass objects with text, and it replaces the string as it arises. For example, the text:

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

I have objects "user" and "site" . I want to replace the lines specified inside ${} with my equivalent values ​​from objects. This is the same as replacing objects in a speed template.

+80
java string reflection velocity
Sep 07 '10 at 2:48
source share
8 answers

Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, and then inserts formatted lines into the template in the appropriate places.

 Object[] params = new Object[]{"hello", "!"}; String msg = MessageFormat.format("{0} world {1}", params); 
+116
Sep 07 2018-10-10T00:
source share

Use the StrSubstitutor from Apache Commons Lang.

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

He will do it for you (and open source ...)

  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}."; StrSubstitutor sub = new StrSubstitutor(valuesMap); String resolvedString = sub.replace(templateString); 
+125
Sep 7 '10 at 5:17
source share

I put together a small test implementation of this. The main idea is to call format and go to the format string and map objects, as well as the names that they have locally.

The conclusion is as follows:

My dog ​​is called fido, and Jane Doe belongs to 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 does not compile due to unhandled exceptions. But this makes the code much easier to read.

In addition, I do not like that you have to build the map in code yourself, but I do not know how to programmatically get the names of local variables. The best way to do this is to remember to place the object on the map immediately after creating it.

The following example shows the results you want in 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 appropriate.

+18
Sep 07 2018-10-10T00:
source share

My preferred method is String.format() , because it is single and does not require third-party libraries:

 String result = String.format("Hello! My name is %s, I'm %s.", NameVariable, AgeVariable); 

I very often use this in exception messages, for example:

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

Hint: you can enter as many variables as you want, because format() uses Varargs

+13
Jan 08 '19 at 9:26
source share

Here is a diagram of how you could do this. It should be relatively simple to implement it as real code.

  1. Create a map of all the objects that will be referenced in the template.
  2. Use a regular expression to find references to variables in the template and replace them with values ​​(see Step 3). The Matcher class comes in handy for searching and replacing.
  3. Split the variable name into a dot. user.name will become user and name . Find user on the map to get the object, and use reflection to get the name value from the object. Assuming your objects have standard retrieval methods, you will look for the getName method and call it.
+5
Sep 07 '10 at 3:01
source share

There are several expression language implementations that do this for you, it may be preferable to use your own implementation, or if your requirements grow, see, for example, JUEL and MVEL

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

Also see the message Stackflow post JSTL / JSP EL (expression language) in a non-JSP context (stand-alone)

+4
Sep 07 2018-10-10T00:
source share

There is nothing out of the box comparable to speed, since speed was written to solve this particular problem. The closest thing you can try is to look in 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 as the formatting options in Java, so that it doesn't exactly scratch your itch, but you can try :).

0
Sep 07 2018-10-09T00:
source share

I use GroovyShell in Java to parse a 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); 
0
Jun 25 '19 at 10:04 on
source share



All Articles