it-swarm.com.de

Wie ersetze ich einen Token-Satz in einem Java-String?

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();
}
100
Mark

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();
63
laginimaineb

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);
94
Paul Morie

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));
41
A. Knauf

Sie könnten versuchen, eine Vorlagenbibliothek wie Apache Velocity zu verwenden.

http://velocity.Apache.org/

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.
40
hallidave

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);
    }
}
23
Li Ying
System.out.println(MessageFormat.format("Hello {0}! You have {1} messages", "Join",10L));

Ausgabe: Hallo Join! Sie haben 10 Nachrichten "

16
user2845137
String.format("Hello %s Please find attached %s which is due on %s", name, invoice, date)
9

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.

8
Ricardo Marimon

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();
}
3
mihu86

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

1
Li Ying
1
Marcel

Ich benutzte

String template = "Hello %s Please find attached %s which is due on %s";

String message = String.format(template, name, invoiceNumber, dueDate);
0
mtwom

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:

  • Haben Sie viele dieser Vorlagen in der Anwendung?
  • Benötigen Sie die Möglichkeit, die Vorlagen zu ändern, ohne die Anwendung neu zu starten?
  • Wer wird diese Vorlagen verwalten? Ein Java-Programmierer oder ein Business-Analyst, der an dem Projekt beteiligt ist?
  • Müssen Sie Logik in Ihre Vorlagen einfügen, z. B. bedingten Text, der auf Werten in den Variablen basiert? 
  • Benötigen Sie die Möglichkeit, andere Vorlagen in eine Vorlage aufzunehmen?

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.

0
Francois Gravel

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"
0
AR1