在Java中使用Matcher时出现无限循环

时间:2020-02-24 08:10:49

标签: java regex

我正在学习正则表达式,并且我有这段代码片段:

baseUrl

尝试另一种方式:

private static final String FILE_BEGINNING_PATTERN = "^(,Share %)";

public static void main(String[] args) {
    String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

    Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);
    if (beginningFileMatcher.find()) {
        System.out.println("Regex match!");
    }

    // find() method starts at the beginning of this matcher's region, or, if
    // a previous invocation of the method was successful and the matcher has
    // not since been reset, at the first character not matched by the previous
    // match.
    //

    int count = 0;
    while (beginningFileMatcher.find()) { // find not match, we need beginningFileMatcher.reset() but its not 
        // thread-safe.
        count++;
        System.out.println("COUNT ++++++++++++++ :" + count);
    }
}

我已经在上面的片段中对此问题发表了评论。有谁能解释为什么?非常感谢!

4 个答案:

答案 0 :(得分:4)

问题是您每次都在Matcher条件下创建一个新的if实例,并且while循环在这里阻塞:

if (beginningFilePattern.matcher(s).find()) {

在这里:

while (beginningFilePattern.matcher(s).find())

通过创建Matcher的新实例,您将失去该状态的先前状态,并且每次都启动匹配操作。

还请注意在if循环之前删除while条件,以使count正确。

您可以使用以下代码解决此问题:

String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);

// find() method starts at the beginning of this matcher's region, or, if
// a previous invocation of the method was successful and the matcher has
// not since been reset, at the first character not matched by the previous
// match.
//

int count = 0;
while (beginningFileMatcher.find()) { // find not match, we need beginningFileMatcher.reset() but its not 
    if (count == 0)
        System.out.println("Regex match!");
    // thread-safe.
    count++;
    System.out.println("COUNT ++++++++++++++ :" + count);
}

//try another way.
String s = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";
Pattern beginningFilePattern = Pattern.compile(FILE_BEGINNING_PATTERN);
Matcher matcher = beginningFilePattern.matcher(s);

int countCount = 0;
while (matcher.find()) { // make sure to use matcher object
    if (countCount == 0)
        System.out.println("Thread-safe regex match!");
    countCount++;
    System.out.println("COUNT ++++++++++++++ :" + countCount);
} 

答案 1 :(得分:1)

每个版本的代码都有一个不同的问题。

对于版本2(无限循环):在循环中创建匹配器。这意味着在每次迭代中,都会从String的开头开始有一个新的匹配器。因此,对find的调用将始终返回相同的结果(如果有的话)。

您需要做的第一个解决方案是创建一个匹配器,然后通过循环调用find来使用它。

问题是您在两个不同的地方致电find。首先在if块中,查看您的String中是否有匹配项,然后在循环中。

如果字符串仅包含1个匹配结果怎么办?

  • 结果在if块中返回
  • countCount设置为0
  • while循环尝试查找下一个匹配项,但没有匹配项
  • 代码显示COUNT : 0

如果在循环之前不重置匹配器,则需要将if块中的结果计数到计数器中。这是更改最少的解决方案:

final static String FILE_BEGINNING_PATTERN = "^(,Share %)";

public static void main(String[] args) {
    String str = ",Share %,\"Date Purchased\",Display Name,Address,Phone,Fax,Mobile,Email,";

    Matcher beginningFileMatcher = Pattern.compile(FILE_BEGINNING_PATTERN).matcher(str);

    int count = 0;
    if (beginningFileMatcher.find()) {
        System.out.println("Regex match!");
        count++; // already a match, increment the counter
    }

    while (beginningFileMatcher.find()) { 
        count++;
        System.out.println("COUNT ++++++++++++++ :" + count);
    }
}

另一种方法是删除if块并仅使用while循环。

答案 2 :(得分:0)

您可以Matcher reset()

重置此匹配器。
重置匹配器将丢弃其所有显式状态信息,并将其附加位置设置为零。匹配器的区域设置为默认区域,即其整个字符序列。该匹配器区域边界的锚定和透明度不受影响。

如果您希望它具有线程安全性,请将其放在10.2块中

答案 3 :(得分:0)

我认为问题在于,当您调用beginningFilePattern.matcher(s).find()时,您正在while条件内创建匹配器的新实例。这些新匹配器中的每一个将从头开始再次检查,而不是尝试查找下一个匹配器。您应该尝试确保reset()通话威胁的安全性,但保持相同的匹配器实例。