Java регулярное выражение для извлечения и замены по значению - PullRequest
3 голосов
/ 19 июня 2019

Строка ввода

${abc.xzy}/demo/${ttt.bbb}
test${kkk.mmm}

РЕЗУЛЬТАТ World / demo / Hello testSystem

Текст в фигурных скобках является ключом к моим свойствам.Я хочу заменить эти свойства значениями времени выполнения.

Я могу сделать следующее, чтобы получить соответствие регулярному выражению, но что я должен вставить в логику замены, чтобы изменить $ {..}, сопоставленный с соответствующим временем выполнениязначение во входной строке.

Pattern p = Pattern.compile("\\{([^}]*)\\}");
Matcher m = p.matcher(s);
while (m.find()) {
  // replace logic comes here
}

Ответы [ 4 ]

3 голосов
/ 19 июня 2019

Альтернативой может быть использование сторонней библиотеки, такой как Apache Commons Text. У них класс StringSubstitutor выглядит очень многообещающе.

Map valuesMap = HashMap();
valuesMap.put("abc.xzy", "World");
valuesMap.put("ttt.bbb", "Hello");
valuesMap.put("kkk.mmm", "System");

String templateString = "${abc.xzy}/demo/${ttt.bbb} test${kkk.mmm}"
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);

Для получения дополнительной информации ознакомьтесь с Javadoc https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringSubstitutor.html

1 голос
/ 19 июня 2019

Вы можете использовать следующее решение:

String s = "${abc.xzy}/demo/${ttt.bbb}\ntest${kkk.mmm}";
Map<String, String> map = new HashMap<String, String>();
map.put("abc.xzy", "World");
map.put("ttt.bbb", "Hello");
map.put("kkk.mmm", "System");
StringBuffer result = new StringBuffer();
Matcher m = Pattern.compile("\\$\\{([^{}]+)\\}").matcher(s);
while (m.find()) {
    String value = map.get(m.group(1));
    m.appendReplacement(result, value != null ? value : m.group());
}
m.appendTail(result);
System.out.println(result.toString());

См. Java-демо онлайн , вывод:

World/demo/Hello
testSystem

регулярное выражение

\$\{([^{}]+)\}

См. Демонстрация регулярных выражений . Он соответствует строке ${, затем захватывает любые 1+ символов, отличные от { и }, в группу 1, а затем соответствует }. Если значение «Группа 1» присутствует на карте в качестве ключа, заменой является значение ключа, в противном случае сопоставленный текст вставляется туда, где он был во входной строке.

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

Ответ The_Cute_Hedgehog хорош, но включает в себя зависимость.
В ответе Виктора Стрибежева отсутствует особый случай.

Мой ответ нацелен на использование встроенного регулярного выражения java и попытается улучшить ответ Wiktor Stribiżew.(Улучшение только в Java-коде, регулярное выражение в порядке)

Улучшения:

  • Использование StringBuilder быстрее, чем StringBuffer
  • Начальное StringBuilder(int)(s.length()*1.2), избегайте многократного перемещения памяти в случае большого входного шаблона s.
  • Избегайте, чтобы специальные символы регулярного выражения приводили к неправильному результату appendReplacement (например, "cost: $100").Вы можете исправить эту проблему в коде Wiktor Stribiżew, выбрав символ $ в строке замены, как этот value.replaceAll("\\$", "\\\\\\$")

Вот улучшенный код:

        String s = "khj${abc.xzy}/demo/${ttt.bbb}\ntest${kkk.mmm}{kkk.missing}string";
        Map<String, String> map = new HashMap<>();
        map.put("abc.xzy", "World");
        map.put("ttt.bbb", "cost: $100");
        map.put("kkk.mmm", "System");
        StringBuilder result = new StringBuilder((int)(s.length()*1.2));
        Matcher m = Pattern.compile("\\$\\{([^}]+)\\}").matcher(s);
        int nonCaptureIndex = 0;
        while (m.find()) {
            String value = map.get(m.group(1));
            if (value != null) {
                int index = m.start();
                if (index > nonCaptureIndex) {
                    result.append(s.substring(nonCaptureIndex, index));
                }
                result.append(value);
                nonCaptureIndex = m.end();
            }
        }
        result.append(s.substring(nonCaptureIndex, s.length()));
        System.out.println(result.toString());
0 голосов
/ 19 июня 2019

Ваше регулярное выражение должно включать в себя доллар. Также достаточно сделать ленивую внутреннюю группу, чтобы в результирующий ключ String не было включено }.

String regex = "\\$\\{(.+?)\\}";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while (m.find()) {
    String key = m.group(1); // This is your matching group (the one in braces).
    String value = someMap.get(key);    
    s.replaceFirst(regex, value != null ? value : "missingKey");

    m = p.matcher(s); // you could alternatively reset the existing Matcher, but just create a new one, for simplicity's sake.
}

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

...