Замена строки в Java, похожая на шаблон скорости - PullRequest
72 голосов
/ 07 сентября 2010

Существует ли какой-либо механизм замены String в Java, где я могу передавать объекты с текстом, и он заменяет строку по мере ее появления.
Например, текст:

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

У меня есть объекты "user" и "site".Я хочу заменить строки, указанные внутри ${}, эквивалентными значениями из объектов.Это то же самое, что мы заменяем объекты в шаблоне скорости.

Ответы [ 8 ]

114 голосов
/ 07 сентября 2010

Используйте Apache Commons Lang.

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

Он сделает это за вас (и с открытым исходным кодом ...)

 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);
111 голосов
/ 07 сентября 2010

Посмотрите на класс java.text.MessageFormat, MessageFormat берет набор объектов, форматирует их, а затем вставляет отформатированные строки в шаблон в соответствующих местах.

Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
17 голосов
/ 07 сентября 2010

Я собрал небольшую тестовую реализацию этого. Основная идея состоит в том, чтобы вызвать format и передать строку формата, а также карту объектов и имена, которые они имеют локально.

Вывод следующего:

Моего пса зовут Фидо, и Джейн Доу владеет им.

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

Примечание. Не компилируется из-за необработанных исключений. Но это делает код намного проще для чтения.

Кроме того, мне не нравится, что вы сами должны создавать карту в коде, но я не знаю, как получить названия локальных переменных программным путем. Лучший способ сделать это - не забыть поместить объект на карту, как только вы его создадите.

В следующем примере вы получите результаты, которые вы хотите получить из своего примера:

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

Я должен также упомянуть, что я понятия не имею, что такое скорость, поэтому я надеюсь, что этот ответ уместен.

8 голосов
/ 08 января 2019

Мой предпочтительный способ - String.format(), потому что он единственный:

String result = String.format("Hello! My name is %s, I'm %s.", NameVariable, AgeVariable); 

Я очень часто использую это в сообщениях об исключениях, таких как:

throw new Exception(String.format("Unable to login with email: %s", email));

Подсказка: вы можете ввести столько переменных, сколько захотите, потому что format() использует Varargs

5 голосов
/ 07 сентября 2010

Вот схема того, как вы могли бы сделать это.Должно быть относительно просто реализовать его как реальный код.

  1. Создать карту всех объектов, на которые будут ссылаться в шаблоне.
  2. Используйте регулярное выражение для поиска ссылок на переменныев шаблоне и замените их значениями (см. шаг 3).Класс Matcher пригодится для поиска и замены.
  3. Разделите имя переменной по точке.user.name станет user и name.Найдите на карте user, чтобы получить объект, и используйте отражение , чтобы получить значение name от объекта.Предполагая, что ваши объекты имеют стандартные методы получения, вы будете искать метод getName и вызывать его.
4 голосов
/ 07 сентября 2010

Существует пара реализаций языка выражений, которые делают это для вас, может быть предпочтительнее использования вашей собственной реализации по мере роста ваших требований, см., Например, JUEL и MVEL

Мне нравится и я успешно использовал MVEL хотя бы в одном проекте.

Также см. Сообщение Stackflow JSTL / JSP EL (язык выражений) в не JSP (автономном) контексте

0 голосов
/ 25 июня 2019

Я использую GroovyShell в Java для разбора шаблона с Groovy GString:

Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
0 голосов
/ 07 сентября 2010

Из коробки нет ничего, что было бы сопоставимо со скоростью, так как скорость была написана для решения именно этой проблемы. Самое близкое, что вы можете попробовать, это посмотреть на Formatter

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

Тем не менее, насколько мне известно, средство форматирования было создано для обеспечения возможностей форматирования в Java на языке C, поэтому он может не полностью поцарапать ваш зуд, но вы можете попробовать :).

...