Java正则表达式以按值提取和替换

时间:2019-06-19 07:22:02

标签: java regex regex-group

输入字符串

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

结果     世界/演示/你好     测试系统

大括号内的文本是我的属性的关键。我想用运行时值替换这些属性。

我可以执行以下操作来获取正则表达式匹配项,但是我应该在替换逻辑中添加什么以更改与输入字符串中的相应运行时值匹配的$ {..}。

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

4 个答案:

答案 0 :(得分:3)

替代方法可能是使用第三方库,例如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 :(得分:1)

您可以使用以下解决方案:

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 demo online,输出:

World/demo/Hello
testSystem

正则表达式为

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

请参见the regex demo。它匹配${字符串,然后将{}以外的任何1个以上的字符捕获到组1中,然后匹配}。如果“组1”值作为键出现在“地图”中,则替换项为键值,否则,匹配的文本将被粘贴回输入字符串中的位置。

答案 2 :(得分:0)

您的正则表达式需要包含美元。另外,使内部组变得懒惰就足以在结果键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.
}

您可以通过提取光标位置并自行替换字符串来简化此操作。但是无论哪种方式,您都需要重置匹配器,因为否则它将在旧的String上进行解析。

答案 3 :(得分:0)

The_Cute_Hedgehog的回答很好,但包含依赖性。
WiktorStribiżew的答案缺少一个特殊情况。

我的答案旨在使用Java内置正则表达式,并尝试从WiktorStribiżew的答案中进行改进。 (仅在Java代码中改进,正则表达式可以)

改进:

  • 使用StringBuilderStringBuffer
  • 初始StringBuilder能够(int)(s.length()*1.2),避免在输入模板s大的情况下多次重定位内存。
  • 避免使用正则表达式特殊字符导致appendReplacement错误的结果(例如"cost: $100")。您可以通过替换$这样的替换字符串中的value.replaceAll("\\$", "\\\\\\$")字符来解决WiktorStribiżew代码中的问题,例如 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());

以下是改进的代码:

Factor 1    Factor 2        Year    value
A            green          2016     1.2
A            green          2017     1.9
B            yellow         2017      3
B            yellow         2018      8
相关问题