Java lambda与正则表达式不生成精确的字符串结果

时间:2016-04-07 18:43:57

标签: java regex lambda

此java lambda替换以$(开头并以)结尾的Map预定义值的字符串:

SortedMap<String, String> map = new TreeMap<String, String>();
map.put("test", "REPLACE");
String update = Arrays.stream("$(test) (test)      (test2)".split("\\(\\$|\\)"))
.map(token -> map.getOrDefault(token, token))
.collect(Collectors.joining(""));

System.out.println(update);

这会打印REPLACE (test (test2

这几乎按预期工作,但右括号已从(test&amp; (test2。我是否需要更新正则表达式,或者可以修改lambda以生成:

REPLACE (test) (test2)

2 个答案:

答案 0 :(得分:1)

问题是您匹配可能不匹配的$()。您只需要在)后跟$($(后跟)匹配。

解决方案1:使用Matcher#appendReplacementCallback

您可以使用简单的正则表达式来匹配$(...)字符串并捕获其中的文本以从地图中获取令牌,并在旅途中执行替换&#34;&#34;匹配时:

SortedMap<String, String> map = new TreeMap<String, String>();
map.put("test", "REPLACE");
String update = "$(test) (test)      (test2)";
Matcher m = Pattern.compile("\\$\\(([^)]*)\\)").matcher(update);
StringBuffer sb = new StringBuffer();
while (m.find()) {
   m.appendReplacement(sb, map.getOrDefault(m.group(1), m.group(1)));
}
m.appendTail(sb);
System.out.println(sb);

请参阅IDEONE demo

解决方案2:将Lambda与Split和Lookarounds

一起使用

免责声明 此方法仅适用于不那么长的字符串

您也可以使用外观。随着前瞻,没有问题,它是无限宽度。使用lookbehind,我们可以依赖受约束的宽度lookbehind(使用限制量词而不是+*):

SortedMap<String, String> map = new TreeMap<String, String>();
map.put("test", "REPLACE");
String update = Arrays.stream("$(test) (test)      (test2)"
    .split("\\$\\((?=[^)]*\\))|(?<=\\$\\([^(]{0,1000})\\)"))
    .map(token -> map.getOrDefault(token, token))
    .collect(Collectors.joining(""));

System.out.println(update); // => REPLACE (test)      (test2)

请参阅IDEONE demo

正则表达式现在写着:

  • \$\((?=[^)]*\)) - 匹配$(后面跟着)以外的0 +字符,然后是)
  • | - 或
  • (?<=\$\([^(]{0,1000})\) - 匹配前面带有)的{​​{1}}以外的0-1000(应该足够)字符的(

答案 1 :(得分:1)

您可以使用地图keySet

上的流缩小功能执行此操作
public static String replaceKeywords(
        final String template, 
        final Map<String, String> map
) {
    return map.keySet().stream().reduce(template, 
            (acc, key) -> acc.replaceAll("\\$\\(" + key + "\\)", map.get(key)));
}

用法:

Map<String, String> map = new TreeMap<String, String>();
map.put("test", "FOO");
map.put("test2", "BAR");

System.out.println(replaceKeywords("$(test) $(test2)      (test2)", map));

输出:

FOO BAR      (test2)