模式匹配器在无限循环中替换循环

时间:2017-09-03 04:38:27

标签: java regex

我有以下周期:

public class Main {

    public static void main (String[] args){
        String test = "#{value} lorem ipsum #{value} lorem ipsum";
        String regex = "(#\\{)([^}]*)(})";

        Pattern callPattern = Pattern.compile(regex);
        Matcher callMatcher = callPattern.matcher(test);

        while (callMatcher.find()) {
            test = callMatcher.replaceFirst(generate());
        }

        System.out.println(test);
    }

    private static String generate(){
        Random random = new Random();
        return String.valueOf(random.nextInt(100));
    }

}

执行陷入了我的while循环。我过去使用过类似的算法,为什么这个算法被卡住了?它似乎能够替换第一次出现,但随后发现但从未替换第二次出现。

3 个答案:

答案 0 :(得分:2)

在你的情况下,匹配器的原因在while循环中保持相同:

Matcher callMatcher = callPattern.matcher(test);

while (callMatcher.find()) { // same value for matcher
     test = callMatcher.replaceFirst(generate()); // you just keep updating the same #{value} everytime
}

将其更改为:

Matcher callMatcher = callPattern.matcher(test);

while (callMatcher.find()) {
    test = callMatcher.replaceFirst(generate());
    callMatcher = callPattern.matcher(test); // updates the matcher with replaced text
}

答案 1 :(得分:2)

您也可以完全避免使用匹配器,而只需依赖基本字符串函数String#matchesString#replaceFirst

String test = "#{value} lorem ipsum #{value} lorem ipsum";
while (test.matches(".*#\\{[^}]*\\}.*")) {
    test = test.replaceFirst("#\\{[^}]*\\}", generate());
}
System.out.println(test);

<强>输出:

87 lorem ipsum 57 lorem ipsum

在这里演示:

Rextester

答案 2 :(得分:0)

问题并非那么简单。在这段代码中确实如此:

elementList = [g1,  g2,  g3,  g4,  g5]
for num in range(len(elementList)):
    if num == 0:
        temp = elementList[num]
    else:
        temp = temp + elementList[num]

分配给 Matcher callMatcher = callPattern.matcher(test); while (callMatcher.find()) { test = callMatcher.replaceFirst(generate()); 不会替换匹配器中的字符串。

但是,这并不能完全解释这种情况,因为test通常会找到匹配的 next 。取决于callMatcher.find()循环体内的内容,这意味着while循环可能仅执行两次。那么为什么在这种情况下无限循环?

它与重置的匹配器有关。 while的{​​{3}}说:

  

此方法从此匹配器区域的开头开始,或者,如果是   以前的方法调用是成功的,匹配器有   从没有重置,在第一个字符不匹配   上一场比赛。

句子的后半部分意味着如果未重置匹配器,则find()将找到该模式的 next 出现,这意味着find()将只能成功两次,然后find()循环将退出。但是javadocwhile中的replaceFirst()说明了这一点:

  

此方法首先重置此匹配器。

因此,由于匹配器已重置,Matcher每次都会从头开始搜索,而不是最后一次匹配的位置。这可以解释您的评论中的问题,关于代码在其他地方工作的原因。可能是你没有调用任何重置匹配器的东西。

处理这种情况的最佳方法,就是使用find()appendReplacement来替换每个模式的情况。 appendTail的{​​{3}}有一个很好的示例,展示了如何使用它。