Explain Codes LogoExplain Codes Logo

String replacement in java, similar to a velocity template

java
string-replacement
template-engineering
java-8
Alex KataevbyAlex KataevΒ·Nov 16, 2024
⚑TLDR

Turn to Java's Pattern and Matcher classes for efficient template string replacement. Match templates with a regex pattern and substitute with corresponding values from a map.

import java.util.regex.*; import java.util.*; public class TemplateReplacer { public static String replace(String template, Map<String, String> values) { Matcher matcher = Pattern.compile("\\$\\{(.+?)\\}").matcher(template); StringBuffer result = new StringBuffer(); while (matcher.find()) { // Who needs a placeholder when you've got values? πŸš€ matcher.appendReplacement(result, values.getOrDefault(matcher.group(1), "NoValue")); } return matcher.appendTail(result).toString(); } public static void main(String[] args) { String result = replace("Hello, ${name}!", Map.of("name", "World")); // The name's World. Hello, World! System.out.println(result); } }

This compact code snippet serves as a quick, fully operational way for placeholder replacement without external libraries. Efficiency at its finest!

Going beyond, exploring options

Apache Commons Text: The external aide

When in need of a higher abstraction, let's not forget our friend, Apache Commons Text. It equips you with StringSubstitutor simplifying template processing:

<!-- Declare your new friendship in your pom.xml --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.9</version> <!-- Stay in sync with the latest version --> </dependency>

Then, let the substitutor do its magic:

import org.apache.commons.text.StringSubstitutor; Map<String, String> values = Map.of("name", "Alice"); StringSubstitutor substitutor = new StringSubstitutor(values); // Who's got the power? Substitutor's got the power! πŸ¦Έβ€β™‚οΈ String result = substitutor.replace("Hello, ${name}!"); System.out.println(result); // Hello, Alice!

MessageFormat: The native trooper

Here comes a Java-native alternative no less in counterparts:

import java.text.MessageFormat; public class TemplateFormatter { public static String format(String pattern, Object... arguments) { // Passing down messages – the Java style! return MessageFormat.format(pattern, arguments); } public static void main(String[] args) { String result = format("Hello, {0}!", "Earth"); System.out.println(result); // Hello, Earth! } }

Reflection: Making mirrors work for you

Use reflection to smartly map values to placeholders when handling object fields:

import java.lang.reflect.Field; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ReflectiveReplacer { public static String replace(String template, Object data) throws IllegalAccessException { Matcher matcher = Pattern.compile("\\$\\{(.+?)\\}").matcher(template); StringBuffer result = new StringBuffer(); while (matcher.find()) { String placeholder = matcher.group(1); Field field = data.getClass().getDeclaredField(placeholder); field.setAccessible(true); Object value = field.get(data); // Watch in the mirror, the value appears! matcher.appendReplacement(result, value.toString()); } return matcher.appendTail(result).toString(); } }

Yet, remember, with great power of reflection comes great responsibility for performance and security.

The convenient path: Using String.format()

When your pattern is straightforward and a map seems overkill:

String result = String.format("Hello, %s!", "Multiverse"); // Et voila, the Universe was born! System.out.println(result); // Hello, Multiverse!

Perfect for modest use cases with positional placeholders and variadic arguments.

The flex path: Regex and the Matcher class

When you need customize and complex replacement logic comes into play, raw regex and the Matcher class are the superheroes:

Pattern pattern = Pattern.compile("Hello, (\\w+)!"); Matcher matcher = pattern.matcher("Hello, Regex!"); if (matcher.matches()) { // I spy with my Regex eye... System.out.println("Match found: " + matcher.group(1)); // Match found: Regex }

Building for the future: Code structure and readability

Prioritize meaningful variable names and systematic classes when working these solutions into your code. This paves the way for enduring maintainability of your work.

Beyond the horizon of string replacement

Special cases management

Consider escaping special characters in replacements when deploying the Matcher append methods. Also, don't forget to guard against the potential null values:

String escapedReplacement = Matcher.quoteReplacement(value); matcher.appendReplacement(result, escapedReplacement);

Cage of performance

Be aware of performance when dealing with large templates or a large number of replacements. Optimize, when necessary, armed with the invaluable tools of profiling and performance tuning.

Compatibility: The farsight

Keeping in mind compatibility with the diversified Java versions is crucial. Restrict yourself to the APIs that are backported and enjoy the vast reach!