2013-05-08 18 views
8

W danym String jak tenJak zastąpić zastępczy w łańcuchu wzorkiem SimpleDateFormat

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

muszę wymienić customer i yyyyMMdd znacznik czasu.

Aby zastąpić symbol zastępczy customer, można użyć StrSubstitutor z Apache Commons. Ale jak wymienić SimpleDateFormat? Pracujemy w środowisku wiosennym, więc może Spring EL jest opcją?

Znacznik dla symboli zastępczych nie jest poprawiony, jest w porządku, jeśli inna biblioteka wymaga zmian składniowych.

Ten niewielki testów pokazuje 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); 
} 
+1

czy ta część zawsze jest ostatnim folderem w strukturze katalogów? –

+0

Nie, w niektórych innych raportach jest pośrodku. Lub w nazwie pliku. To tylko przykład. – d0x

Odpowiedz

24

Dlaczego nie używasz MessageFormat zamiast?

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

Albo z String.format

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

Podoba mi się sposób z nazwanymi zmiennymi. Ponieważ String pochodzi z innego modułu. Nie wiedzą, w których używam. Z 'MessageFormat' muszę komunikować się Index 0 = klient, 1 = aktualna data, 2 = .... hm .... – d0x

+0

Czy formatowanie szczegółów implementacji nie jest? Jak to jest "narażone" na twoich klientów? Czy nie jest to po prostu wywołanie metody z wpisanymi parametrami? – NilsH

8

As NilsH zasugerował MessageFormat jest naprawdę miły dla tego celu. Aby mieć nazwach zmiennych można ukryć MessageFormat za swojej klasie:

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; 
    } 
} 

I trzeba dostosować testcase:

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); 
} 

usunąłem rodzajowych i zastąpienia tych sznurkiem. Również isPlaceholder i getPlaceholderValue jest zakodowany na sztywno i oczekuje się składni $ {wartość}.

Ale to tylko pomysł rozwiązania problemu. Aby to zrobić, można użyć metod z StrSubstitutor (wystarczy użyć lub utworzyć FormattedStrSubstitutor extends StrSubstitutor).

Również można użyć na przykład $ d {wartość} do formatowania dat i $ foo {value} formatowania foo.

UPDATE

nie można spać bez pełnego rozwiązania. Możesz dodać tę metodę do FormattedStrSubstitutor Klasa:

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; 
} 

Twój testcase jest jak w swoim pytaniu (małe zmiany zastępczy):

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); 
} 

samo ograniczenie jak poprzednio; bez generics i fix prefiks i sufiks dla placeholder.

Powiązane problemy