Java generating Strings with placeholders
Asked Answered
L

13

85

I'm looking for something to achieve the following:

String s = "hello {}!";
s = generate(s, new Object[]{ "world" });
assertEquals(s, "hello world!"); // should be true

I could write it myself, but It seems to me that I saw a library once which did this, probably it was the slf4j logger, but I don't want to write log messages. I just want to generate strings.

Do you know about a library which does this?

Length answered 28/6, 2013 at 12:20 Comment(3)
#3695730Cichocki
The slf4J uses org.slf4j.helpers.MessageFormatter The code looks like this: String str = "Hello this is {} string {}"; MessageFormatter.format(str, new String[]{"hello", "world", "blah"}).getMessage();Bowles
Does this answer your question? String replacement in java, similar to a velocity templateOpiumism
I
101

See String.format method.

String s = "hello %s!";
s = String.format(s, "world");
assertEquals(s, "hello world!"); // should be true
Inch answered 28/6, 2013 at 12:23 Comment(2)
how to replace two Strings in the same format() ? example String.format("%s %s!", ["hello", "world"]); is this possible?Bernardinebernardo
@Bernardinebernardo use String.format("Hello %s welcome to %s!", "Carlos. V", "JAVA"); will print Hello Carlos. V welcome to JAVA! and you can use as many %s as you can. :)Cristobalcristobalite
F
46

StrSubstitutor from Apache Commons Lang may be used for string formatting with named placeholders:

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

https://commons.apache.org/proper/commons-lang/javadocs/api-3.4/org/apache/commons/lang3/text/StrSubstitutor.html :

Substitutes variables within a string by values.

This class takes a piece of text and substitutes all the variables within it. The default definition of a variable is ${variableName}. The prefix and suffix can be changed via constructors and set methods.

Variable values are typically resolved from a map, but could also be resolved from system properties, or by supplying a custom variable resolver.

Example:

String template = "Hi ${name}! Your number is ${number}";

Map<String, String> data = new HashMap<String, String>();
data.put("name", "John");
data.put("number", "1");

String formattedString = StrSubstitutor.replace(template, data);
Fogged answered 5/10, 2016 at 12:41 Comment(2)
The StrSubstitutor is deprecated, see this SO post for a work around.Metagalaxy
The org.apache.commons.text.StringSubstitutor from org.apache.commons:commons-text:x.y has taken it's place. Simply drop that one in and you're good to go without deprecation warnings.Concha
S
42

This can be done in a single line without the use of library. Please check java.text.MessageFormat class.

Example

String stringWithPlaceHolder = "test String with placeholders {0} {1} {2} {3}";
String formattedStrin = java.text.MessageFormat.format(stringWithPlaceHolder, "place-holder-1", "place-holder-2", "place-holder-3", "place-holder-4");

Output will be

test String with placeholders place-holder-1 place-holder-2 place-holder-3 place-holder-4
Strep answered 27/12, 2019 at 7:24 Comment(1)
This is the best solution when adding localization as the place holder order changes for different languages .Czarevna
H
14

If you can change the format of your placeholder, you could use String.format(). If not, you could also replace it as pre-processing.

String.format("hello %s!", "world");

More information in this other thread.

Heliacal answered 28/6, 2013 at 12:23 Comment(0)
F
9

There are two solutions:

Formatter is more recent even though it takes over printf() which is 40 years old...

Your placeholder as you currently define it is one MessageFormat can use, but why use an antique technique? ;) Use Formatter.

There is all the more reason to use Formatter that you don't need to escape single quotes! MessageFormat requires you to do so. Also, Formatter has a shortcut via String.format() to generate strings, and PrintWriters have .printf() (that includes System.out and System.err which are both PrintWriters by default)

Fullbodied answered 28/6, 2013 at 12:23 Comment(6)
I remember reading/testing that MessageFormat was pretty slow.Cichocki
@Cichocki meh, I don't know, my message bundle API proposes both since I have ResourceBundle compatibility... But I personally always use Formatter.Fullbodied
I am not sure to be honest - and in most situations it won't make a difference anyway.Cichocki
MessageFormat does have a few advantages over Formatter though, particularly the possibility to embed ChoiceFormat expressions.Acarus
@Acarus not a problem, Formatter has Formattable, which is even more powerful ;)Fullbodied
@Fullbodied I wouldn't say that's a clearly better option in all circumstances, the canonical example being format strings like Found {0,choice,0#nothing|1#one thing|{0} things}Acarus
T
7

You won't need a library; if you are using a recent version of Java, have a look at String.format:

String.format("Hello %s!", "world");
Tricho answered 28/6, 2013 at 12:23 Comment(0)
R
6

If you can tolerate a different kind of placeholder (i.e. %s in place of {}) you can use String.format method for that:

String s = "hello %s!";
s = String.format(s, "world" );
assertEquals(s, "hello world!"); // true
Russophobe answered 28/6, 2013 at 12:23 Comment(0)
P
4

Justas answer is outdated so I'm posting up to date answer with apache text commons.

StringSubstitutor from Apache Commons Text may be used for string formatting with named placeholders: https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringSubstitutor.html

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

This class takes a piece of text and substitutes all the variables within it. The default definition of a variable is ${variableName}. The prefix and suffix can be changed via constructors and set methods. Variable values are typically resolved from a map, but could also be resolved from system properties, or by supplying a custom variable resolver.

Example:

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

// Build StringSubstitutor
StringSubstitutor sub = new StringSubstitutor(valuesMap);

// Replace
String resolvedString = sub.replace(templateString);
Pacificia answered 13/8, 2020 at 22:36 Comment(0)
I
4

If you want to use some string to different placeholders, you could use pointers like this:

String.format("%1$s %2$s %1$s", "startAndEndText", "middleText");
Involucel answered 25/1, 2022 at 10:6 Comment(0)
C
1

if you are user spring you can like this:

String template = "hello #{#param}";
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("param", "world");
String value = new SpelExpressionParser().parseExpression(template, new TemplateParserContext()).getValue(context, String.class);
System.out.println(value);

out put:

hello world
Calumniation answered 22/11, 2022 at 3:51 Comment(0)
O
1

Java is going to have string templates (from version 21, as a preview feature).

See the string templates proposal (JEP 430) here.

It will be something along the lines of this:

String name = "World";
String info = STR."Hello \{name}!";
System.out.println(info); // Hello World!

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

val name = "World"
val info = "Hello $name!"
println(info) // Hello World!

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

Opiumism answered 18/12, 2022 at 15:27 Comment(0)
S
0

The suggestion by https://stackoverflow.com/users/4290127/himanshu-chaudhary works quite well:

String str = "Hello this is {} string {}";     
str = MessageFormatter.format(str, "hello", "world").getMessage();
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.8.0-beta4</version>
</dependency>
Sturm answered 1/12, 2021 at 5:22 Comment(0)
B
0

In case you do not want to rely on any third-party library, and you do want to use unnamed, unnumbered placeholders like SLF4j does, like

This {} is a placeholder, and this {} is another one

I came up with this approach:

public static String format(String m, Object... placeholder) {
    final int[] counter = {0};
    return Pattern.compile("\\{}").matcher(m).replaceAll(matchResult -> {
        if (counter[0] == placeholder.length)
            throw new RuntimeException("Some placeholder arguments missing for " + m);
        return Matcher.quoteReplacement(String.valueOf(placeholder[counter[0]++]));
    });
}

It does not validate for unnecessary placeholders, only for missing placeholder arguments. Can be easily added in case you care about that case.

Using Matcher.quoteReplacement is optional, but in case you are using file paths mandatory. Otherwise slashes will be removed

Barrel answered 7/5 at 11:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.