Замена переменных в строках и правильное разрешение экранирования

1

У меня есть проект, в котором есть переменные, которые нужно вводить в Строки. Давайте сделаем вид, что у меня есть написанный метод и его имя 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}.

  • 1
    Я думаю, что третий тест не имеет смысла. Если в фигурных скобках есть литерал \, значение в фигурных скобках не является переменным
  • 0
    @bowmore Согласен. Дело в том, почему я не хочу писать свою реализацию :)
Теги:
string-matching

2 ответа

1
Лучший ответ

Я думаю, что это можно сделать с регулярными выражениями:

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

}

оговорка: могут потребоваться дополнительные испытания

2

Вам нужна только одна строка, если вы используете 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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню