Java正则表达式中Matcher类的find方法多次调用的匹配问题

Java正则表达式中Matcher类的find方法多次调用的匹配问题,第1张

Java正则表达式中Matcher类的find方法多次调用匹配问题

首先,看下面的代码,我以为它三次调用find()方法都会返回true,但实际上并不是。

public class Demo {
    public static void main(String[] args) {
        String str = "hello 123!";
        String regex = "(\d+)";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
        System.out.println(matcher.find());// false
        System.out.println(matcher.find());// false
    }
}

阅读了Java正则匹配中matcher()和find()的配对问题后认为matcher与find()是一一对应的,但后来发现事实并非如此,看下面的代码:

public class Demo {
    public static void main(String[] args) {
        String str = "hello 123! hello 456! hello 789!";
        String regex = "(\d+)";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
        System.out.println(matcher.find());// true
        System.out.println(matcher.find());// true
        System.out.println(matcher.find());// false
    }
}

打印的结果分别是:true、true、true、false。如果按照上面文章的结论应该打印的结果是:true、false、false、false。

为什么会这样呢?我们看它的源码,可能会有一点思路:

    
    public boolean find() {
        int nextSearchIndex = last;
        if (nextSearchIndex == first)
            nextSearchIndex++;

        // If next search starts before region, start it at region
        if (nextSearchIndex < from)
            nextSearchIndex = from;

        // If next search starts beyond region then it fails
        if (nextSearchIndex > to) {
            for (int i = 0; i < groups.length; i++)
                groups[i] = -1;
            return false;
        }
        return search(nextSearchIndex);
    }

将上面的方法注释翻译成中文,如下:

尝试找到与模式匹配的输入序列的下一个子序列。
此方法在此匹配器区域的开头开始,或者,如果该方法的先前调用成功且此后匹配器尚未重置,则在与先前匹配不匹配的第一个字符处开始。
如果匹配成功,则可以通过start 、 end和group方法获得更多信息。
返回:
当且仅当输入序列的子序列与此匹配器的模式匹配时才为真

即如果该方法的先前调用成功且此后匹配器尚未重置,则在与先前匹配不匹配的第一个字符处开始。的情况。

我们的测试文本是hello 123! hello 456! hello 789!,字符串中的每一个字符及其下标如下图所示:
当我们第一次调用find()方法的时候,一定会搜索到数字的。
而第二次调用find()方法则从下标为9的字符开始查找起,也能找到与正则表达式相匹配的字符串"456",如下图:
而第三次调用find()方法则从下标为20的字符开始查找起,也能找到与正则表达式相匹配的字符串"789",如下图:
而第四次调用find()方法从下标t为31的字符开查找起,找不到能够与正则表达式相匹配的字符串,返回false。

通过debug调试到find()方法内,查看nextSearchIndex局部变量的值跟上面说的一样。

到此我们应该能够明白第一份代码中find()方法为什么输出的结果是true、false、false了。因为find()方法的查找会从上一次匹配成功后不匹配的第一个字符开始查找,而上一份代码整个字符串中只有一份能够匹配,所以后面的调用也就返回false了。

所以对于第一份代码中的问题解决,可以像参考文章中所说的那样,重新再生成一个matcher:

public class Demo {
    public static void main(String[] args) {
        String str = "hello 123!";
        String regex = "(\d+)";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
        matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
        matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
    }
}

或者在每次调用后再执行reset()方法重置:

public class Demo {
    public static void main(String[] args) {
        String str = "hello 123!";
        String regex = "(\d+)";
        Matcher matcher = Pattern.compile(regex).matcher(str);
        System.out.println(matcher.find());// true
        matcher.reset();
        System.out.println(matcher.find());// true
        matcher.reset();
        System.out.println(matcher.find());// true
    }
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5138483.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-17
下一篇 2022-11-17

发表评论

登录后才能评论

评论列表(0条)

保存