【问题标题】:Regex replace with Stream正则表达式替换为 Stream
【发布时间】:2016-10-09 19:48:39
【问题描述】:

好奇,有没有办法用 Java Stream 写这个?

private final static Pattern decodePattern = Pattern.compile("&#(\\d+);");

StringBuffer buf = new StringBuffer();

Matcher m = decodePattern.matcher(somestring);
while (m.find()) {
    m.appendReplacement(buf, String.valueOf((char) Integer.parseInt(m.group(1))));
}
m.appendTail(buf);

String decodeString = buf.toString();

【问题讨论】:

标签: java regex java-stream


【解决方案1】:

Java 9

在Java 9 中重载Matcher 类的方法可以实现更简洁的代码:
public String replaceAll​(Function<MatchResult,String> replacer)。基本上我们现在可以替换像

这样的代码
StringBuffer sb = new StringBuffer();
while(matcher.find()){
    matcher.appendReplacement(sb, /*create replacement*/);
}
matcher.appendTail(sb);
String result = sb.toString;

String replaced = matcher.replaceAll(match -> /*create replacement*/);

例如

String replaced = Pattern.compile("\\b\\w")
                         .matcher("foo bar baz")
                         .replaceAll(match -> match.group().toUpperCase());
//replaced: "Foo Bar Baz"

还增加了对匹配模式的元素流的支持:public Stream<MatchResult> results​(),但 IMO 你的循环看起来不太适合流。即使使用results(),您的代码也会如下所示:

//BTW Java 9 provides support for StringBuilder beside StringBuffer 
//for appendReplacement/appendTail

Matcher matcher = ...
StringBuilder buf = new StringBuilder(); 

matcher.results()
       .map(result -> String.valueOf((char) Integer.parseInt(result.group(1))) )
       .forEach(replacement -> matcher.appendReplacement(buf, replacement));
matcher.appendTail(buf);

String decodeString = buf.toString();

所以它看起来不太干净。


Java 8

在 Java 8 中,Pattern 和 Matcher 类在流支持方面没有太大变化。只有 Pattern 接收到 public Stream<String> splitAsStream(CharSequence input) 方法,但它创建了元素流,其中 pattern 表示我们要拆分的 delimiter,而不是我们要查找的文本。

如果您想在 Java 8 中简化代码,请编写您自己的方法,在该方法中您将提供 Matcher 和将匹配的内容(最好由 MatchResult 或 Matcher 表示,以便它可以访问 group(...) 方法)映射到替换应该代替它。

这种方法可能如下所示:

public static String replaceMatches(Matcher m, Function<MatchResult, String> mapping){
    
    StringBuffer sb = new StringBuffer();
    while(m.find()){
        MatchResult matchResult = m.toMatchResult();
        m.appendReplacement(sb, mapping.apply(matchResult));
    }
    m.appendTail(sb);
    
    return sb.toString();
}

你可以像这样使用它:

Pattern p = Pattern.compile("\\b\\w");
Matcher m = p.matcher("foo bar baz");

String result = replaceMatches(m, mr -> mr.group().toUpperCase());

System.out.println(result);

结果:Foo Bar Baz

【讨论】:

  • 您的示例使用Pattern.compile("\\b\\w")replaceMatches(m, mr -&gt; mr.group().toUpperCase()) 会更简单、更高效...
猜你喜欢
  • 2012-05-05
  • 1970-01-01
  • 2016-07-17
  • 2012-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-24
  • 2015-01-24
相关资源
最近更新 更多