Is there a way to render a string like "Hello,% (name) s'% {'name': 'Felix'} in Java?

In Python, we can do this easily:

data = {'name':'Felix'} s = 'Hello, %(name)s' % data s 'Hello, Felix' 

Is there a similar way in Java to implement the same thing?

PS: Sorry for the incomprehensible question. usage example: we have a card in which the key values โ€‹โ€‹are stored, the Template should indicate only the key on the card, then the key value will be in the place where the key is in the template.

+4
source share
5 answers

In this case, you need a template engine, such as speed or freemarker, to use a data structure like a map to render a string template, for this there is no built-in module in java. like this (with speed):

 public static void main(String[] args) { Context context = new VelocityContext(); context.put("appid", "9876543d1"); context.put("ds", "2013-09-11"); StringWriter sw = new StringWriter(); String template = "APPID is ${appid} and DS is ${ds}"; Velocity.evaluate(context, sw, "velocity", template); System.out.println(sw.toString()); } 
0
source

AFAIK you can use String#format for this:

 String name = "Felix"; String s = String.format("Hello, %s", name); System.out.println(s); 

Will open

 Hello, Felix 

More on how to use String#format formatting can be found on the java.util.Formatter syntax

+3
source

You want the String.format method .

 String data = "Hello, %s"; String updated = String.format(data, "Felix"); 
+1
source

If you want to replace only lines with lines, then the code from the second part of my answer would be better

The Java Formatter class does not support the form %(key)s , but instead you can use %index$s where the index is counted from 1 as in this example

 System.out.format("%3$s, %2$s, %1s", "a", "b", "c"); // indexes 1 2 3 

exit:

 c, b, a 

So, all you have to do is create some array that will contain the values โ€‹โ€‹used in the template and change the key names to their corresponding indices (incremented by 1 since the first index used by Formatter is written as 1$ not like 0$ like we expect for array indices).

Here is an example of a method that will do this for you

 // I made this Pattern static and put it outside of method to compile it only once, // also it will match every (xxx) that has % before it, but wont include % static Pattern formatPattern = Pattern.compile("(?<=%)\\(([^)]+)\\)"); public static String format(String pattern, Map<String, ?> map) { StringBuffer sb = new StringBuffer(); List<Object> valuesList = new ArrayList<>(); Matcher m = formatPattern.matcher(pattern); while (m.find()) { String key = m.group(1);//group 1 contains part inside parenthesis Object value = map.get(key); // If map doesn't contain key, value will be null. // If you want to react somehow to null value like throw some // Exception // now is the good time. if (valuesList.contains(value)) { m.appendReplacement(sb, (valuesList.indexOf(value) + 1) + "\\$"); } else { valuesList.add(value); m.appendReplacement(sb, valuesList.size() + "\\$"); } } m.appendTail(sb); return String.format(sb.toString(), valuesList.toArray()); } 

Using

 Map<String, Object> map = new HashMap<>(); map.put("name", "Felix"); map.put("age", 70); String myPattern = "Hi %(emptyKey)s! My name is %(name)s %(name)s and I am %(age)s years old"; System.out.println(format(myPattern, map)); 

exit:

 Hi null! My name is Felix Felix and I am 70 years old 

As you can see, you can use the same key several times (in our case name ), and if your card does not contain the key used in your String template (for example, emptyKey ), it will be replaced with null .


The above version is for setting a data type of type s d , etc., but if your data will always be replaced by strings, you can skip String.format(sb.toString(), valuesList.toArray()) and replace all your keys with values โ€‹โ€‹earlier.

Here is a simpler version that will only accept a card with a key-value relationship <String,String> .

 static Pattern stringsPattern = Pattern.compile("%\\(([^)]+)\\)s\\b"); public static String formatStrings(String pattern, Map<String, String> map) { StringBuffer sb = new StringBuffer(); Matcher m = stringsPattern.matcher(pattern); while (m.find()) { // we can't use null as replacement so we need to convert it to String // first. We can do it with String.valueOf method m.appendReplacement(sb, String.valueOf(map.get(m.group(1)))); } m.appendTail(sb); return sb.toString(); } 
+1
source

If you need more advanced methods, such as i18n support, you can use the advanced features of the message format

for example: in the langage property files you add the 'template' property, which is your message

 template = At {2,time,short} on {2,date,long}, \ we detected {1,number,integer} spaceships on \ the planet {0}. 

then you can format your valrieres by passing arguments in an array:

 Object[] messageArguments = { "Mars", new Integer(7), new Date() }; 

You call the formatter like this:

 MessageFormat formatter = new MessageFormat(""); formatter.setLocale(currentLocale); formatter.applyPattern(messages.getString("template")); String output = formatter.format(messageArguments); 

a detailed example is here http://docs.oracle.com/javase/tutorial/i18n/format/messageFormat.html

0
source

Source: https://habr.com/ru/post/1493561/


All Articles