Zastępowanie łańcuchów w Javie, podobne do szablonu velocity

Czy istnieje jakiś mechanizm zastępczy String w Javie, w którym mogę przekazywać obiekty z tekstem, a on zastępuje ciąg znaków w miarę jego występowania.
Na przykład tekst to:

Hello ${user.name},
    Welcome to ${site.name}. 

Obiekty, które mam to "user" i "site". Chcę zastąpić łańcuchy podane wewnątrz ${} równoważnymi wartościami z obiektów. Jest to to samo, co zastępujemy obiekty w szablonie prędkości.

Author: Joe, 2010-09-07

6 answers

Użyj Apache commons lang.

Https://commons.apache.org/proper/commons-lang/

Zrobi to za Ciebie (i jego open source...)

 Map<String, String> valuesMap = new HashMap<String, String>();
 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);
 102
Author: JH.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-26 02:16:20

Spójrz na java.text.MessageFormat class, MessageFormat pobiera zbiór obiektów, formatuje je, a następnie wstawia sformatowane ciągi znaków do wzorca w odpowiednich miejscach.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
 94
Author: RealHowTo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-26 15:37:46

Rzuciłem razem małą implementację testową tego. Podstawową ideą jest wywołanie format i przekazanie w formacie ciągu znaków oraz mapy obiektów i nazw, które mają lokalnie.

Wyjście następującej treści to:

Mój pies ma na imię fido, a Jane Doe jest jego właścicielem.
public class StringFormatter {

    private static final String fieldStart = "\\$\\{";
    private static final String fieldEnd = "\\}";

    private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
    private static final Pattern pattern = Pattern.compile(regex);

    public static String format(String format, Map<String, Object> objects) {
        Matcher m = pattern.matcher(format);
        String result = format;
        while (m.find()) {
            String[] found = m.group(1).split("\\.");
            Object o = objects.get(found[0]);
            Field f = o.getClass().getField(found[1]);
            String newVal = f.get(o).toString();
            result = result.replaceFirst(regex, newVal);
        }
        return result;
    }

    static class Dog {
        public String name;
        public String owner;
        public String gender;
    }

    public static void main(String[] args) {
        Dog d = new Dog();
        d.name = "fido";
        d.owner = "Jane Doe";
        d.gender = "him";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("d", d);
        System.out.println(
           StringFormatter.format(
                "My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.", 
                map));
    }
}

uwaga: nie kompiluje się z powodu nieobsługiwanych wyjątków. Ale to sprawia, że kod jest znacznie łatwiejszy do odczytania.

Poza tym, nie podoba mi się, że musisz konstruować mapę siebie w kodzie, ale nie wiem jak zaprogramować nazwy zmiennych lokalnych. Najlepszym sposobem na to jest, aby pamiętać, aby umieścić obiekt na mapie, jak tylko go utworzysz.

Poniższy przykład daje wyniki, które chcesz uzyskać z twojego przykładu:

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<String, Object>();
    Site site = new Site();
    map.put("site", site);
    site.name = "StackOverflow.com";
    User user = new User();
    map.put("user", user);
    user.name = "jjnguy";
    System.out.println(
         format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}

powinienem również wspomnieć, że nie mam pojęcia, co to jest Velocity, więc mam nadzieję, że ta odpowiedź jest istotna.

 15
Author: jjnguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-07 04:20:06

Oto zarys, jak możesz to zrobić. Wdrożenie go jako rzeczywistego kodu powinno być stosunkowo proste.

  1. utwórz mapę wszystkich obiektów, do których będą się odwoływać w szablonie.
  2. użyj wyrażenia regularnego, aby znaleźć odniesienia do zmiennych w szablonie i zastąpić je ich wartościami (patrz krok 3). Klasa Matcher przyda się do wyszukiwania i wymiany.
  3. podziel nazwę zmiennej na kropkę. user.name stałoby się user i name. Poszukaj user na mapie, aby uzyskać obiekt i użyj reflection , aby uzyskać wartość name z obiektu. Zakładając, że Twoje obiekty mają standardowe gettery, poszukasz metody getName i ją wywołasz.
 4
Author: casablanca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-07 03:01:05

Istnieje kilka implementacji języka wyrażeń, które robią to za Ciebie, może być lepiej niż używanie własnej implementacji, gdy lub jeśli twoje wymagania rosną, zobacz na przykład JUEL i MVEL

Lubię i z powodzeniem używam MVEL w co najmniej jednym projekcie.

Zobacz także post Stackflow JSTL / JSP EL (język wyrażeń) w kontekście non JSP (standalone)

 4
Author: Christoffer Soop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:45

Nie ma nic, co byłoby porównywalne z velocity, ponieważ velocity zostało napisane, aby rozwiązać dokładnie ten problem. Najbliższą rzeczą, którą możesz wypróbować, jest sprawdzenie Formatera

Http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html

Jednak formater o ile wiem został stworzony, aby zapewnić C jak opcje formatowania w Javie, więc może nie zarysować dokładnie swędzenie, ale zapraszamy do wypróbowania :).

 0
Author: Mike Milkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-07 03:55:32