Java Matcher类中的appendReplacement()和appendTail()方法适用于StringBuilder吗?

6

是否有一种使用StringBuilder替代StringBuffer的Matcher.appendReplacement()和Matcher.appendTail()的替代方案?

有没有一种“简单”的方法,可以将调用Matcher时使用StringBuffer的Java代码转换为使用StringBuilder呢?

谢谢, 詹姆斯

3个回答

8
短答案是,还没有。直到Java 9才有Matcher.appendReplacement(StringBuilder,String)Matcher.appendTail(StringBuilder)方法添加到API中。
在那之前,如果您不需要组替换,则仍然可以使用这个“简单”的解决方案:
Matcher m = PATTERN.matcher(s);
StringBuilder sb = new StringBuilder();
int pos = 0;
while(m.find()) {
    sb.append(s, pos, m.start());
    pos = m.end();
    sb.append("replacement")
}
sb.append(s, pos, s.length());

即使您需要进行组替换,也只是“适度”困难:
Matcher m = PATTERN.matcher(s);
StringBuilder sb = new StringBuilder();
int pos = 0;
while(m.find()) {
    sb.append(s, pos, m.start());
    pos = m.end();
    if (m.start(1) >= 0) {                  // check if group 1 matched
        sb.append(s, m.start(1), m.end(1)); // replace with group 1
    }
}
sb.append(s, pos, s.length());

1
天啊:你看过 Matcher.appendReplacement() 的代码吗?太复杂了,难以置信。 - kevinarpe
对于短字符串,您可以承受内存开销并使用String - Maarten Bodewes

4

简而言之,不行。

这是根据最新的Java 8 API所述。

然而,StringBuffer的一个重载构造函数接受一个CharSequence作为参数,而StringBuilder(与StringBuffer一样)IS-A CharSequence

例如:

matcher.appendReplacement(
    new StringBuffer(yourOriginalStringBuilder), "yourReplacement"
);

编辑

从Java 9开始,提供了一种重载形式,它接受一个StringBuilder - 请参见API此处


不使用StringBuffer的原因之一是为了避免线程同步。由于StringBuffer是同步的,您的代码实际上会在更多的对象上进行同步。 而且它根本不起作用,因为StringBuffer不再适用于传递给其构造函数和appendReplacement附加到...无效的StringBuilder。 - krzychek
@krzychek 我的回答有点旧 (2016),是 Java 9 发布前的,所以没有 StringBuilder 重载方法,可以在此处看到链接。不过,使用旧的方法签名时被阻塞的风险是很小的,因为你必须在多个线程上调用相同的 StringBufferappendReplacement 方法,这本身就意味着设计有问题。 - Mena
使用旧的方法签名时,阻塞的风险是很小的。同步是Buffer和Builder之间的主要区别,它存在于单个线程上调用之外。如果需要并发访问,则应引入同步,而不是阻止威胁(或重新设计解决方案)。 - krzychek
无论如何,JIT编译器使同步影响在大多数情况下可以忽略不计,我看到的主要问题是,在新的StringBuffer(builder)调用之后,匹配器不再改变builder实例,这可能会误导Java新手。(我已经编辑示例) - krzychek

0
所以,对于读者来说:JDK 9的完整代码和多个替换(例如 "Hello ${name}, check ${email}"):
private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(\\w+)}");

Matcher matcher = PLACEHOLDER_PATTERN.matcher(value)
if(matcher.find()){
    StringBuilder sb = new StringBuilder();
    while (p.matcher.find()) {
       String key = p.matcher.group(1);
       Object obj = getObject(key, map);
       p.matcher.appendReplacement(sb, obj.toString());
    }
    p.matcher.appendTail(sb);
    return sb.toString;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接