2017-09-03 58 views
1

我有以下循环:模式匹配替换周期在一个无限循环

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循环。过去我使用过类似的算法,那为什么这个卡住了?它似乎能够取代第一次出现,但后来发现但从未取代第二次。

回答

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

谢谢。有用。现在我想知道其他类似的周期是如何工作的。我在同一个项目中至少有另一个。 – EBM

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

0

的问题不是这么简单。这是真的,在此代码:

Matcher callMatcher = callPattern.matcher(test); 

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

分配给test不替换字符串中的匹配。

但是,这并不能完全说明情况,因为callMatcher.find()通常会发现下一个匹配的发生。取决于while循环体内的内容,这意味着while循环可能只有被执行两次。那么为什么它在这种情况下无限循环?

它与匹配器被重置有关。该javadocfind()说:

该方法始于此匹配的区域的开始,或者,如果该方法的 以前的调用是成功的,并且匹配具有 不是因为被复位,在第一个字符不前场比赛的比赛结果为 。

句子的后半部分意味着,如果匹配不复位,然后find()会发现下一个出现的格局,这意味着find()只成功了两次,然后while循环会出口。但javadoc说,这大约replaceFirst()Matcher

此方法首先重置匹配器。

因此,由于匹配器被重置,所以find()将从每次开始搜索,而不是最后一次匹配的位置。这可能会解释您评论中的问题,以及代码为什么在其他地方有效。这可能是因为你没有调用任何重置匹配器的东西。

也许处理这种情况的最好方法就是使用appendReplacementappendTail来代替每次出现的模式。 javadocappendReplacement有一个很好的例子显示如何使用它。