正则表达式替换为Stream

时间:2016-10-09 19:48:40

标签: java regex java-stream

通过好奇心,有没有办法用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();

1 个答案:

答案 0 :(得分:2)

Java 9

清除代码可以通过Matcher类中的Java 9方法重载来实现:
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收到了public Stream<String> splitAsStream(CharSequence input)方法,但是它创建了一个元素流,其中pattern表示我们要分割的 delimiter ,而不是我们想要找到的文本。 / p>

如果你想简化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