Замена строк в java, аналогично шаблону скорости
Есть ли какой-либо механизм замены String
в Java, где я могу передавать объекты с текстом, и он заменяет строку по мере ее возникновения.
Например, текст:
Hello ${user.name},
Welcome to ${site.name}.
У меня есть объекты "user"
и "site"
. Я хочу заменить строки, указанные внутри ${}
, своими эквивалентными значениями из объектов. Это то же самое, что мы заменяем объекты в шаблоне скорости.
Ответы
Ответ 1
Взгляните на класс java.text.MessageFormat
, MessageFormat принимает набор объектов, форматирует их, а затем вставляет отформатированные строки в шаблон в соответствующих местах.
Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
Ответ 2
Используйте StrSubstitutor
из 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);
Ответ 3
Я собрал небольшую тестовую реализацию этого. Основная идея состоит в вызове format
и переходе в строку формата и карту объектов, а также имена, которые у них есть локально.
Вывод следующего:
Моя собака называется fido, и Джейн Доу принадлежит ему.
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));
}
Я должен также упомянуть, что я понятия не имею, что такое Velocity, поэтому я надеюсь, что этот ответ уместен.
Ответ 4
Мой предпочтительный способ - String.format()
, потому что он единый и не требует сторонних библиотек:
String message = String.format("Hello! My name is %s, I'm %s.", name, age);
Я очень часто использую это в сообщениях об исключениях, например:
throw new Exception(String.format("Unable to login with email: %s", email));
Подсказка: вы можете ввести столько переменных, сколько захотите, потому что format()
использует Varargs
Ответ 5
Вот схема того, как вы могли бы сделать это. Должно быть относительно просто реализовать его как реальный код.
- Создайте карту всех объектов, на которые будут ссылаться в шаблоне.
- Используйте регулярное выражение, чтобы найти ссылки на переменные в шаблоне и заменить их значениями (см. Шаг 3). Класс Matcher пригодится для поиска и замены.
- Разбить имя переменной на точку.
user.name
станет user
и name
. Найдите user
на карте, чтобы получить объект, и используйте отражение, чтобы получить значение name
из объекта. Предполагая, что ваши объекты имеют стандартные методы получения, вы будете искать метод getName
и вызывать его.
Ответ 6
Существует несколько реализаций языка выражений, которые делают это для вас, может быть предпочтительнее использовать вашу собственную реализацию, или если ваши требования растут, см., например, JUEL и MVEL
Мне нравится и успешно использовал MVEL по крайней мере в одном проекте.
Также см. сообщение Stackflow post JSTL/JSP EL (язык выражений) в контексте без JSP (автономный)
Ответ 7
Нет ничего из коробки, сравнимого со скоростью, так как скорость была написана для решения именно этой проблемы. Самое близкое, что вы можете попробовать, - это посмотреть в Formatter
http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html
Однако форматировщик, насколько мне известно, был создан, чтобы предоставить C как параметры форматирования в Java, чтобы он не царапал точно ваш зуд, но вы можете попробовать:).
Ответ 8
Я использую 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);