【问题标题】:matches.find() with replaceAll()match.find() 和 replaceAll()
【发布时间】:2018-03-01 04:18:38
【问题描述】:

我是 Java 新手,我在现有代码中发现了一个循环,它看起来应该是一个无限循环(或者具有非常不受欢迎的行为),它实际上可以工作。

你能解释一下我错过了什么吗?我认为它应该是无限的原因是,根据此处的文档 (https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#replaceAll-java.lang.String-),调用 replaceAll 将重置匹配器(此方法首先重置此匹配器。然后扫描输入序列...... em>)。所以我认为下面的代码会替换它,然后再次调用 find(),这将从头开始。而且它会一直找到相同的字符串,因为你可以看到字符串只是被包裹在一个标签中。

如果不明显,Pattern 和 Matcher 是 java.util.regex 中的类。

String aTagName = getSomeTagName()
String text = getSomeText()
Pattern pattern = getSomePattern()
Matcher matches = pattern.matcher(text);
while (matches.find()) {
    text = matches.replaceAll(String.format("<%1$s> %2$s </%1$s>", aTagName, matches.group()));
}

为什么不是这样?

【问题讨论】:

  • 努佩。因为你要替换火柴,所以它不会再存在了……我想……我不知道。已经很晚了,我很累,因此不合理。让我召唤 Uni。
  • 同样好奇的是,甚至不需要 while 循环,因为 replaceAll 将一次性完成工作并重置匹配项。我认为一个简单的 if 在这种情况下可以正常工作。如果是这样的话,我不知道你为什么需要检查matches.find,一个简单的replace all应该可以工作。

标签: java regex


【解决方案1】:

我和你一样怀疑这段代码很可能是无意的,因为replaceAll 改变了状态,并且由于它扫描要替换的字符串,结果是只执行了1次搜索并且声明组用于用该组替换所有搜索。

String text = "abcdEfg";
Pattern pattern = Pattern.compile("[a-z]");
Matcher matches = pattern.matcher(text);
while (matches.find()) {
    System.out.println(text); // abcdEfg
    text = matches.replaceAll(matches.group());
    System.out.println(text); // aaaaEaa
}

replaceAll 告诉匹配器扫描字符串,它最终将指针移动到末尾以耗尽整个字符串的状态。然后find 继续搜索(从当前状态——结束,而不是开始),但搜索已经用尽了。


为每个组适当地迭代和替换的正确方法之一可能是使用appendReplacement

String text = "abcdEfg";
Pattern pattern = Pattern.compile("[a-z]");
Matcher matches = pattern.matcher(text);
StringBuffer sb = new StringBuffer();
while (matches.find()) {
    matches.appendReplacement(sb, matches.group().toUpperCase());
    System.out.println(text); // some of ABCDEFG
}
matches.appendTail(sb);
System.out.println(sb); // ABCDEFG

【讨论】:

    【解决方案2】:

    以下示例表明,如果您使用全部替换,则没有理由调用 while 循环。在这两种情况下,答案都是

    th 夏天吗? Th 非常炎热的夏天。 不是吗?

    import java.util.regex.*;
    
    public class Test {
        public static void main(String[] args) {
            String text = "is this a summer ? This is very hot summer. isn't it?";
            String tag = "b";
            String pattern = "is";
            System.out.println(question(text,tag,pattern));
            System.out.println(alt(text,tag,pattern));
        }
    
        public static String question(String text, String tag, String p) {
            Pattern pattern = Pattern.compile(p);
            Matcher matcher= pattern.matcher(text);
            while (matcher.find()) {
                text = matcher.replaceAll(
                    String.format("<%1$s> %2$s </%1$s>",
                    tag, matcher.group()));
            }
            return text;
        }
    
        public static String alt(String text, String tag, String p) {
            Pattern pattern = Pattern.compile(p);
            Matcher matcher= pattern.matcher(text);
            if(matcher.find())
                return matcher.replaceAll(
                    String.format("<%1$s> %2$s </%1$s>",
                    tag, matcher.group()));
            else
                return text;
        }
    
    }
    

    【讨论】:

    • 你知道为什么它不会进入无限循环吗?我认为由于 matcher.replaceAll() 正在重置匹配项,因此 matcher.find() 总是从头开始重新开始,因此 while 条件永远不会为假。
    • 哦,没关系,我猜答案在另一个答案中:“然后 find 继续搜索(从当前状态 - 这是结束,而不是开始),但搜索已经用尽。 "
    猜你喜欢
    • 2019-12-21
    • 1970-01-01
    • 2012-10-08
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 2010-11-30
    • 2020-03-12
    • 1970-01-01
    相关资源
    最近更新 更多