Ich habe die folgende Vorlagenzeichenfolge: "Hello [Name] Please find attached [Invoice Number] which is due on [Due Date]"
.
Ich habe auch String-Variablen für Name, Rechnungsnummer und Fälligkeitsdatum. Wie kann ich die Token in der Vorlage am besten durch die Variablen ersetzen?
(Beachten Sie, dass eine Variable, die ein Token enthält, NICHT ersetzt werden sollte).
EDIT
Dank an @laginimaineb und @ alan-moore, hier ist meine Lösung:
public static String replaceTokens(String text,
Map<String, String> replacements) {
Pattern pattern = Pattern.compile("\\[(.+?)\\]");
Matcher matcher = pattern.matcher(text);
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String replacement = replacements.get(matcher.group(1));
if (replacement != null) {
// matcher.appendReplacement(buffer, replacement);
// see comment
matcher.appendReplacement(buffer, "");
buffer.append(replacement);
}
}
matcher.appendTail(buffer);
return buffer.toString();
}
Der effizienteste Weg wäre die Verwendung eines Matchers, um die Ausdrücke ständig zu finden, sie zu ersetzen und dann den Text an einen String-Builder anzuhängen:
Pattern pattern = Pattern.compile("\\[(.+?)\\]");
Matcher matcher = pattern.matcher(text);
HashMap<String,String> replacements = new HashMap<String,String>();
//populate the replacements map ...
StringBuilder builder = new StringBuilder();
int i = 0;
while (matcher.find()) {
String replacement = replacements.get(matcher.group(1));
builder.append(text.substring(i, matcher.start()));
if (replacement == null)
builder.append(matcher.group(0));
else
builder.append(replacement);
i = matcher.end();
}
builder.append(text.substring(i, text.length()));
return builder.toString();
Ich glaube wirklich nicht, dass Sie dafür eine Template-Engine oder ähnliches benötigen. Sie können die String.format
-Methode wie folgt verwenden:
String template = "Hello %s Please find attached %s which is due on %s";
String message = String.format(template, name, invoiceNumber, dueDate);
Leider ist die oben erwähnte komfortable Methode String.format nur mit Java 1.5 verfügbar (was heutzutage ziemlich Standard sein sollte, aber man weiß nie). Stattdessen können Sie auch die class MessageFormat von Java verwenden, um die Platzhalter zu ersetzen.
Es unterstützt Platzhalter in der Form '{number}', daher würde Ihre Nachricht wie folgt aussehen: "Hallo {0} Bitte finden Sie den Anhang {1}, der am {2} fällig ist". Diese Strings können mithilfe von ResourceBundles (z. B. für die Lokalisierung mit mehreren Gebietsschemata) leicht externalisiert werden. Das Ersetzen würde mit der static-Methode der Klasse MessageFormat erfolgen:
String msg = "Hello {0} Please find attached {1} which is due on {2}";
String[] values = {
"John Doe", "invoice #123", "2009-06-30"
};
System.out.println(MessageFormat.format(msg, values));
Sie könnten versuchen, eine Vorlagenbibliothek wie Apache Velocity zu verwenden.
Hier ist ein Beispiel:
import org.Apache.velocity.VelocityContext;
import org.Apache.velocity.app.Velocity;
import Java.io.StringWriter;
public class TemplateExample {
public static void main(String args[]) throws Exception {
Velocity.init();
VelocityContext context = new VelocityContext();
context.put("name", "Mark");
context.put("invoiceNumber", "42123");
context.put("dueDate", "June 6, 2009");
String template = "Hello $name. Please find attached invoice" +
" $invoiceNumber which is due on $dueDate.";
StringWriter writer = new StringWriter();
Velocity.evaluate(context, writer, "TemplateName", template);
System.out.println(writer);
}
}
Die Ausgabe wäre:
Hallo Mark. Die beigefügte Rechnung 42123 finden Sie am 6. Juni 2009.
Sie können die Vorlagenbibliothek für das Ersetzen komplexer Vorlagen verwenden.
FreeMarker ist eine sehr gute Wahl.
http://freemarker.sourceforge.net/
Aber für einfache Aufgaben gibt es eine einfache Dienstprogrammklasse, die Ihnen helfen kann.
org.Apache.commons.lang3.text.StrSubstitutor
Es ist sehr leistungsfähig, anpassbar und einfach zu bedienen.
Diese Klasse nimmt einen Text und ersetzt alle Variablen darin. Die Standarddefinition einer Variablen ist $ {Variablenname} . Präfix und Suffix können über Konstruktoren und Set-Methoden geändert werden.
Variablenwerte werden normalerweise aus einer Karte aufgelöst, können jedoch auch .__ sein. aufgelöst aus den Systemeigenschaften oder durch Angabe einer benutzerdefinierten Variablen Resolver.
Wenn Sie z. B. eine Systemumgebungsvariable in eine Vorlagenzeichenfolge einfügen möchten, Hier ist der Code:
public class SysEnvSubstitutor {
public static final String replace(final String source) {
StrSubstitutor strSubstitutor = new StrSubstitutor(
new StrLookup<Object>() {
@Override
public String lookup(final String key) {
return System.getenv(key);
}
});
return strSubstitutor.replace(source);
}
}
System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L));
Ausgabe: Hallo Join! Sie haben 10 Nachrichten "
String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date)
Dies hängt davon ab, wo sich die tatsächlichen Daten befinden, die Sie ersetzen möchten. Möglicherweise haben Sie eine Karte wie diese:
Map<String, String> values = new HashMap<String, String>();
enthält alle Daten, die ersetzt werden können. Dann können Sie die Karte durchlaufen und alles im String wie folgt ändern:
String s = "Your String with [Fields]";
for (Map.Entry<String, String> e : values.entrySet()) {
s = s.replaceAll("\\[" + e.getKey() + "\\]", e.getValue());
}
Sie können auch über den String iterieren und die Elemente in der Map finden. Dies ist jedoch etwas komplizierter, da Sie den String nach dem [] suchen müssen. Sie können dies mit einem regulären Ausdruck mit Pattern und Matcher tun.
Meine Lösung zum Ersetzen von $ {variable} Stil-Tokens (inspiriert durch die Antworten hier und durch das Spring UriTemplate):
public static String substituteVariables(String template, Map<String, String> variables) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
Matcher matcher = pattern.matcher(template);
// StringBuilder cannot be used here because Matcher expects StringBuffer
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
if (variables.containsKey(matcher.group(1))) {
String replacement = variables.get(matcher.group(1));
// quote to work properly with $ and {,} signs
matcher.appendReplacement(buffer, replacement != null ? Matcher.quoteReplacement(replacement) : "null");
}
}
matcher.appendTail(buffer);
return buffer.toString();
}
Zu Ihrer Information
In der neuen Sprache Kotlin, Können Sie "String Templates" direkt in Ihrem Quellcode verwenden. Keine Drittanbieter-Bibliothek oder Vorlagen-Engine muss die Variablen ersetzen.
Es ist ein Merkmal der Sprache selbst.
Siehe: https://kotlinlang.org/docs/reference/basic-types.html#string-templates
Ich benutzte
String template = "Hello %s Please find attached %s which is due on %s";
String message = String.format(template, name, invoiceNumber, dueDate);
In der Vergangenheit habe ich dieses Problem mit StringTemplate und Groovy Templates gelöst.
Letztendlich sollte die Entscheidung für die Verwendung einer Templating Engine auf folgenden Faktoren beruhen:
Wenn einer der oben genannten Punkte auf Ihr Projekt zutrifft, würde ich die Verwendung einer Templating Engine in Betracht ziehen, von der die meisten diese Funktionalität bieten, und vieles mehr.
Mit Apache Commons Library können Sie einfach Stringutils.replaceEach verwenden:
public static String replaceEach(String text,
String[] searchList,
String[] replacementList)
Aus der Dokumentation :
Ersetzt alle Vorkommen von Strings in einem anderen String.
Eine an diese Methode übergebene Nullreferenz ist ein No-Op. Wenn "search String" oder "ersetzte Zeichenfolge" null ist, wird diese Ersetzung ignoriert . Dies wird sich nicht wiederholen. Rufen Sie das überladene .__ auf, um das Ersetzen zu wiederholen. Methode.
StringUtils.replaceEach(null, *, *) = null
StringUtils.replaceEach("", *, *) = ""
StringUtils.replaceEach("aba", null, null) = "aba"
StringUtils.replaceEach("aba", new String[0], null) = "aba"
StringUtils.replaceEach("aba", null, new String[0]) = "aba"
StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
(example of how it does not repeat)
StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"