it-swarm.com.de

Ersetzen eines Platzhalters in einem String durch ein SimpleDateFormat-Muster

In einem bestimmten String wie diesem

".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"

Ich muss einen customerund einen yyyyMMddZeitstempel ersetzen.

Um den Platzhalter customerzu ersetzen, könnte ich den StrSubstitutorvon Apache Commons verwenden. Aber wie ersetzt man SimpleDateFormatname__? Wir laufen in einer Frühlingsumgebung, vielleicht ist Spring EL eine Option?

Das Markup für die Platzhalter ist nicht festgelegt, es ist in Ordnung, wenn eine andere Bibliothek syntaktische Änderungen benötigt.

Dieser kleine Test zeigt das Problem:

SimpleDateFormat            formatter   = new SimpleDateFormat("yyyyMMdd");

String                      template    = ".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf";

@Test
public void shouldResolvePlaceholder()
{
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");

    final String filledTemplate = StrSubstitutor.replace(this.template, model);

    assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate);
}
10
d0x

Warum verwenden Sie nicht stattdessen MessageFormat ?

String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date);

Oder mit String.format

String result = String.format(".../uploads/%1$s/%2$tY%2$tm%2$td/report.pdf", customer, date);
27
NilsH

Wie NilsH vorschlug, ist MessageFormat für diesen Zweck wirklich schön. Um benannte Variablen zu haben, können Sie MessageFormat hinter Ihrer Klasse ausblenden:

public class FormattedStrSubstitutor {
    public static String formatReplace(Object source, Map<String, String> valueMap) {
        for (Map.Entry<String, String> entry : valueMap.entrySet()) {   
            String val = entry.getValue();
            if (isPlaceholder(val)) {
                val = getPlaceholderValue(val);
                String newValue = reformat(val);

                entry.setValue(newValue);
            }
        }

        return new StrSubstitutor(valueMap).replace(source);
    }

    private static boolean isPlaceholder(String isPlaceholder) {
        return isPlaceholder.startsWith("${");
    }

    private static String getPlaceholderValue(String val) {
        return val.substring(2, val.length()-1);
    }

    private static String reformat(String format) {
        String result = MessageFormat.format("{0,date," + format + "}", new Date());

        return result;
    }
}

Und Sie müssen Ihren Testfall anpassen:

SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");

String template = ".../uploads/${customer}/${dateTime}/report.pdf";

@Test
public void shouldResolvePlaceholder() {
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");
    model.put("dateTime", "${yyyyMMdd}");

    final String filledTemplate = FormattedStrSubstitutor.formatReplace(this.template,
        model);

    assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
        + "/report.pdf", filledTemplate);
}

Ich habe Generika entfernt und durch String ersetzt. Auch isPlaceholder und getPlaceholderValue sind hartcodiert und erwarten die $ {value} -Syntax.

Dies ist jedoch nur die Idee, um Ihr Problem zu lösen. Dazu können Sie die Methoden von StrSubstitutor verwenden (verwenden Sie einfach oder machen Sie FormattedStrSubstitutor extends StrSubstitutor).

Sie können beispielsweise auch $ d {value} für die Datumsformatierung und $ foo {value} für die Foo-Formatierung verwenden.

UPDATE

Könnte nicht ohne volle Lösung schlafen. Sie können diese Methode zur FormattedStrSubstitutor-Klasse hinzufügen:

public static String replace(Object source,
        Map<String, String> valueMap) {

    String staticResolved = new StrSubstitutor(valueMap).replace(source);

    Pattern p = Pattern.compile("(\\$\\{date)(.*?)(\\})");
    Matcher m = p.matcher(staticResolved);

    String dynamicResolved = staticResolved;
    while (m.find()) {
        String result = MessageFormat.format("{0,date" + m.group(2) + "}",
                new Date());

        dynamicResolved = dynamicResolved.replace(m.group(), result);
    }

    return dynamicResolved;
}

Ihr Testfall ist wie in Ihrer Frage (kleine Änderungen im Platzhalter):

SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");

String template = ".../uploads/${customer}/${date,yyyyMMdd}/report.pdf";

@Test
public void shouldResolvePlaceholder() {
    final Map<String, String> model = new HashMap<String, String>();
    model.put("customer", "Mr. Foobar");

    final String filledTemplate =  FormattedStrSubstitutor.replace(this.template,
            model);

    assertEquals(
            ".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
                    + "/report.pdf", filledTemplate);
}

Gleiche Einschränkung wie zuvor; Keine generics und fixes Präfix und Suffix für Platzhalter.

9
Walery Strauch

Sieht so aus, als wäre es so einfach?

static final Pattern DOLLARS = Pattern.compile("\\$\\{([^}]+)}");

public static String resolve(String string, Map<String,String> config) {
    StringBuilder builder = new StringBuilder();
    Matcher matcher = DOLLARS.matcher(string);
    int start = 0;
    while (matcher.find(start)) {
        builder.append(string.substring(start, matcher.start()));
        String property = matcher.group(1);
        String value = config.get(property);
        builder.append(value);
        start = matcher.end();
    }
    builder.append(string.substring(start));
    return builder.toString();
}
0
anydoby