У меня есть проект, в котором есть переменные, которые нужно вводить в Строки. Давайте сделаем вид, что у меня есть написанный метод и его имя replaceVariables
и оно заменяет {varaible}
на foo
.
replaceVariables("This variable should be replaced {variable}")
// "This variable should be replaced foo"
replaceVariables("This variable should NOT be replaced \\{variable\\}")
// "This variable should NOT be replaced {variable}"
replaceVariables("This variable should be replaced \\\\{variable\\\\}")
// "This variable should be replaced \foo\"
Я мог написать собственный парсер, который обнаруживает обратную косую черту и делает все это, но мне действительно кажется, что я изобретаю колесо здесь.
Есть ли реализация этого, которая делает это в библиотеках Apache или Spring? Я знаю theres SPEL от весны, но я чувствую, что на верх. Другая возможность могла бы быть регулярным выражением, но независимо от того, как я пытаюсь создать регулярное выражение, всегда кажется, что негативный взгляд впереди всегда должен был выглядеть 1 раньше, чтобы проверить экранированный \
, иначе вы обнаружите обратную косую черту, но, возможно, обратная косая черта экранирована и т.д. (хотя я вроде бы сосать в регулярных выражениях).
Примечание. Я должен соблюдать соглашение об именах {variableName}
.
Я думаю, что это можно сделать с регулярными выражениями:
public class VariableReplace {
private class Substitution {
private final String variable;
private final String value;
private Substitution(String variable, String value) {
this.variable = variable;
this.value = value;
}
public String getRegex() {
return "((\\\\)*)\\{\\Q" + variable + "\\E\\}";
}
public String getValue() {
return "$1" + value;
}
}
private final List<Substitution> substitutions = new ArrayList<>();
public void replace(String variable, String foo) {
substitutions.add(new Substitution(variable, foo));
}
public String replaceVariables(String s) {
String result = s;
for (Substitution substitution : substitutions) {
result = result.replaceAll(substitution.getRegex(), substitution.getValue());
}
result = result.replaceAll("\\\\(.)", "$1");
return result;
}
}
Класс испытания:
public class VariableReplaceTest {
private VariableReplace variableReplace = new VariableReplace();
@Before
public void setUp() {
variableReplace.replace("variable", "foo");
}
@Test
public void testNormal() {
assertEquals("This variable should be replaced foo", variableReplace.replaceVariables("This variable should be replaced {variable}") );
}
@Test
public void testEscaped() {
assertEquals("This variable should NOT be replaced {variable}", variableReplace.replaceVariables("This variable should NOT be replaced \\{variable\\}") );
}
@Test
public void testDoubleEscaped() {
assertEquals("This variable should be replaced \\foo", variableReplace.replaceVariables("This variable should be replaced \\\\{variable}") );
}
@Test
public void testVariableContainsRegexChars() {
variableReplace.replace("var[iable", "foo");
assertEquals("This variable should be replaced foo", variableReplace.replaceVariables("This variable should be replaced {var[iable}") );
}
}
оговорка: могут потребоваться дополнительные испытания
Вам нужна только одна строка, если вы используете replaceAll()
с регулярным выражением, которое использует отрицательный внешний вид, чтобы утверждать, что фигурная скобка не сбежала:
str.replaceAll("(?<![^\\\\]\\\\\\\\)\\{\\Q" + name + "\\E\\}", value));
Вот несколько тестовых кодов:
String name = "foo", value = "bar";
String[] strs = {"abc {foo} def", "abc \\\\{foo} def", "abc \\\\\\\\{foo} def"};
for (String str : strs)
System.out.println(str + " --> " + str.replaceAll("(?<![^\\\\]\\\\\\\\)\\{\\Q" + name + "\\E\\}", value));
Вывод:
abc {foo} def --> abc bar def
abc \\{foo} def --> abc \\{foo} def
abc \\\\{foo} def --> abc \\\\bar def