正则表达式——非贪婪匹配

在介绍非贪婪匹配前,我们先看一个简单的问题:

给定一个字符串表示的数字,判断该数字末尾0的个数。例如:

    “123000”:3个0 “10100”:2个0 “1001”:0个0

可以很容易地写出该正则表达式:(d+)(0*),Java代码如下:

import java.util.regex.*;

public class Main {
          
   
    public static void main(String[] args) {
          
   
        Pattern pattern = Pattern.compile("(\d+)(0*)");
        Matcher matcher = pattern.matcher("1230000");
        if (matcher.matches()) {
          
   
            System.out.println("group1=" + matcher.group(1)); // "1230000"
            System.out.println("group2=" + matcher.group(2)); // ""
        }
    }
}

然而打印的第二个子串是空字符串""。

实际上,我们期望分组匹配结果是: 但实际的分组匹配结果是这样的: 仔细观察上述实际匹配结果,实际上它是完全合理的,因为d+确实可以匹配后面任意个0。

这是因为正则表达式默认使用贪婪匹配:任何一个规则,它总是尽可能多地向后匹配,因此,d+总是会把后面的0包含进来。

要让d+尽量少匹配,让0*尽量多匹配,我们就必须让d+使用非贪婪匹配。在规则d+后面加个?即可表示非贪婪匹配。我们改写正则表达式如下:

import java.util.regex.*;

public class Main {
          
   
    public static void main(String[] args) {
          
   
        Pattern pattern = Pattern.compile("(\d+?)(0*)");
        Matcher matcher = pattern.matcher("1230000");
        if (matcher.matches()) {
          
   
            System.out.println("group1=" + matcher.group(1)); // "123"
            System.out.println("group2=" + matcher.group(2)); // "0000"
        }
    }
}

因此,给定一个匹配规则,加上?后就变成了非贪婪匹配。

我们再来看这个正则表达式(d??)(9*),注意d?表示匹配0个或1个数字,后面第二个?表示非贪婪匹配,因此,给定字符串"9999",匹配到的两个子串分别是"“和"9999”,因为对于d?来说,可以匹配1个9,也可以匹配0个9,但是因为后面的?表示非贪婪匹配,它就会尽可能少的匹配,结果是匹配了0个9。

小结

正则表达式匹配默认使用贪婪匹配,可以使用?表示对某一规则进行非贪婪匹配。

注意区分?的含义:d??。

经验分享 程序员 微信小程序 职场和发展