Czy istnieje ogólna funkcja zastępowania ciągów podobna do sl4fj?

85

W sl4fj, jeśli chcę skonstruować wiadomość tekstową, jest fajne podejście, które wykorzystuje podstawienia. Na przykład może to być coś takiego:

logger.info("Action {} occured on object {}.", objectA.getAction(), objectB);

Jeśli wymaganych jest więcej niż kilka podstawień, to wygląda to tak:

logger.info("Action {} occured on object {} with outcome {}.", 
    new Object[]{objectA.getAction(), objectB, outcome});

Moje pytanie brzmi: czy istnieje ogólny sposób na utworzenie ciągu znaków (a nie tylko komunikat dziennika slf4j)? Coś jak:

String str = someMethod("Action {} occured on object {}.", objectA.getAction(), objectB);

lub

String str = someMethod("Action {} occured on object {} with outcome {}.", 
    new Object[]{objectA.getAction(), objectB, outcome});

Jeśli znajduje się w standardowej bibliotece Java, czym byłaby ta „someMethod”?

kmccoy
źródło
1
Podziękowania dla tych z odpowiedziami poniżej. Ponadto odkryłem, że to pytanie zostało już zadane tutaj: stackoverflow.com/questions/3114021 . Przepraszam, że opublikowałem mniej więcej duplikat.
kmccoy

Odpowiedzi:

113

String.format

String str = String.format("Action %s occured on object %s.",
   objectA.getAction(), objectB);

Lub

String str = String.format("Action %s occured on object %s with outcome %s.",
   new Object[]{objectA.getAction(), objectB, outcome});

Możesz także użyć pozycji numerycznych, na przykład do przełączania parametrów między:

String str = String.format("Action %2$s occured on object %1$s.",
   objectA.getAction(), objectB);
Scrum Meister
źródło
45

Możesz użyć String.format lub MessageFormat.format

Na przykład,

MessageFormat.format("A sample value {1} with a sample string {0}", 
    new Object[] {"first", 1});

lub po prostu

MessageFormat.format("A sample value {1} with a sample string {0}", "first", 1);
Johan Sjöberg
źródło
1
MessageFormat jest bardzo wszechstronny i potężny, ale w przypadku prostych zamian String.format będzie prawdopodobnie prostszy i mniej ograniczony (np. MessageFormat wymaga podwójnych cudzysłowów).
Kat,
1
nowa liczba całkowita (1) zastąpiona tylko 1 in powyżej, wtedy też będzie działać.
TechnoCrat
25

Jeśli szukasz rozwiązania, w którym możesz zastąpić kilka zmiennych w łańcuchu wartościami, możesz użyć StrSubstitutor .

 Map<String, String> valuesMap = new HashMap<>();
 valuesMap.put("animal", "quick brown fox");
 valuesMap.put("target", "lazy dog");
 String templateString = "The ${animal} jumped over the ${target}.";
 StrSubstitutor sub = new StrSubstitutor(valuesMap);
 String resolvedString = sub.replace(templateString);

Jest zgodny z ogólnie przyjętym wzorcem, w którym można przekazać mapę ze zmiennymi do wartości wraz z nierozpoznanym ciągiem i zwraca rozwiązany ciąg.

Balamurugan Muthiah
źródło
20

Sugerowałbym użycie org.slf4j.helpers.MessageFormatter . Z jego pomocą można stworzyć metodę użyteczności, która używa dokładnie tego samego stylu formatowania, co slf4j:

// utillity method to format like slf4j
public static String format(String msg, Object... objs) {
    return MessageFormatter.arrayFormat(msg, objs).getMessage();
}

// example usage
public static void main(String[] args) {
    String msg = format("This msg is {} like slf{}j would do. {}", "formatted", 4,
            new Exception("Not substituted into the message"));

    // prints "This msg is formatted like slf4j would do. {}"    
    System.out.println(msg); 
}

Uwaga : Jeśli ostatni obiekt w tablicy jest wyjątkiem, nie zostanie on zastąpiony w komunikacie, tak jak w przypadku rejestratora slf4j. Wyjątek byłby dostępny za pośrednictwem MessageFormatter.arrayFormat(msg, objs).getThrowable().

Pete
źródło
3
Twierdzę, że nie jest to dobra odpowiedź do celów ogólnych, ale właściwie dość do tego, o co pytano.
Michael Piefel,
3
Uważam, że to jest dokładnie właściwa odpowiedź. To powinno być najlepsze pod względem wydajności.
Sasa
1
Najlepsza odpowiedź, ponieważ używa dokładnej składni, o którą pytano.
Christoph
szczerze mówiąc, IMHO to jedyna odpowiedź, która faktycznie pasuje do pierwotnego pytania ... bije mnie, dlaczego zajmuje teraz czwarte miejsce ...
raner
0

Wybieram zawinięcie Log4j2 ParameterizedMessage, który został pierwotnie napisany dla Lilith przez Joern Huxhorn:

public static String format(final String messagePattern, Object... arguments) {
    return ParameterizedMessage.format(messagePattern, arguments);
}

Koncentruje się na formacie wiadomości, w przeciwieństwie do SLF4J MessageFormatter, który zawiera niepotrzebne przetwarzanie Throwable.

Zobacz Javadoc:

Obsługuje komunikaty składające się z ciągu formatu zawierającego „{}” reprezentujący każdy wymienny token oraz parametry.

zhouji
źródło