第十三章 字符串 正则匹配Pattern与Matcher

思考:为什么使用正则表达式之前都要经过编译?

思考:正则匹配又是怎么去匹配的?

从算法上分析,对一个字符串进行正则匹配,是拿正则表达式深度遍历整个字符串,也就是用正则表达式去匹配所有可能的子串【也不一定是所有,但肯定是绝大部分】,拿下面的这个例子来说

package 字符串;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * find()可以在输入的任意位置定位正则表达式
 * 而lookingAt()和matches()只有在正则表达式与输入的最开始处就开始匹配时才会成功
 * matches()只有在整个输入都匹配正则表达式时才会成功,而lookingAt()只要输入的第一部分匹配就会成功
* * 找出所有不以大写字母开头的词,不重复的计算其个数 *
@author admin * */ public class TestMatcher { public static void main(String[] args) { String s = "Twas brilling,and the slithy toves\n" + "Did gyre and gimble in the wabe.\n"; System.out.println(s.length()); Matcher m = Pattern.compile("\\w+").matcher(s); System.out.println(m.matches()); } }

代码中正则表达式为"\\w+"  ,  表示匹配一个或多个词字符[a-zA-Z0-9],如果让这个正则表达式去匹配字符串s,【用matches()方法】算法的一般思路就是:

遍历字符串s所有字符,从首字母T开始和这个正则表达式匹配一次,如果匹配继续拿Tw和这个正则表达式匹配一次,如果匹配继续拿Twa和正则表达式匹配一次,就这样一直匹配下去。但是一旦出现某个子串与正则表达式不匹配,就结束程序返回false,上例中可见到Twas 时已经不在满足匹配要求,因为出现了空格。所以匹配过程会在第一次出现不满足正则表达式时就结束返回false。上例程序输出结果为:

false

推荐一篇分析正则表达式的博客(想深入了解的同学可以看看):在这里

从上面分析我们就可以看出为什么使用正则表达式之前都要对正则表达式进行预编译了,因为正则匹配是不断的拿正则表达式去匹配比较字符子串,如果不预编译一次的话,每次匹配比较都要编译一次,显然是没必要的,如果你查看过compile()方法的源码会发现编译过程还是比较负复杂和消耗性能的。

String类自带了一个matches方法,对正则需求不高时,直接使用字符串.matches("正则表达式")即可满足需求:

package 字符串;

/**
 * find()可以在输入的任意位置定位正则表达式
 * 而lookingAt()和matches()只有在正则表达式与输入的最开始处就开始匹配时才会成功
 * 
 * @author admin
 *
 */
public class Regex {

    public static void main(String[] args) {
        String str = "Java now has regular expressions";
        System.out.println(str.matches("^Java.*"));
    }

}

Matcher.find()方法:可以用来在CharSequence中查找更多个匹配。

package 字符串;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * find()可以在输入的任意位置定位正则表达式
 * 而lookingAt()和matches()只有在正则表达式与输入的最开始处就开始匹配时才会成功
 * 
 * 找出所有不以大写字母开头的词,不重复的计算其个数
 * @author admin
 *
 */
public class TestMatcher {

    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        String s = "Twas brilling,and  the slithy toves\n" +
        "Did gyre and gimble in the wabe.\n";
        System.out.println(s.length());
        Matcher m = Pattern.compile("\\w+").matcher(s);
        System.out.println(m.matches());
        
        while(m.find())    //试图从输入字符串中根据正则去寻找下一个子串。
            if(!m.group().matches("[A-Z].*")) {
                //只有在调用过m.find()之后才能使用start/end
                //regionStart和regionEnd分别代表着字符串的起始位置
                System.out.println(m.start()+"=="+m.end()+"=="+m.regionStart()+"=="+m.regionEnd()+"=="+m.group());
                //m.group就是截取start---end位置的子串
                set.add(m.group());
            }
        System.out.println(set.size());
    }

}

控制台:

69
false
5==13==0==69==brilling
14==17==0==69==and
19==22==0==69==the
23==29==0==69==slithy
30==35==0==69==toves
40==44==0==69==gyre
45==48==0==69==and
49==55==0==69==gimble
56==58==0==69==in
59==62==0==69==the
63==67==0==69==wabe
9

每执行一次while循环都切出一块满足正则匹配的字符串。

Matcher.find(int i):其中i表示字符串中的位置,并以其作为搜索的起点。

package 字符串;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * find()可以在输入的任意位置定位正则表达式
 * 而lookingAt()和matches()只有在正则表达式与输入的最开始处就开始匹配时才会成功
 * 
 * 找出所有不以大写字母开头的词,不重复的计算其个数
 * @author admin
 *
 */
public class TestMatcher {

    public static void main(String[] args) {
        String s = "Twas brilling,and  the slithy toves\n";
        System.out.println(s.length());
        Matcher m = Pattern.compile("\\w+").matcher(s);

        int i = 0;
        while(m.find(i)) {//试图从输入字符串中根据正则去寻找下一个子串。
            System.out.println(m.start()+"=="+m.end()+"=="+m.regionStart()+"=="+m.regionEnd()+"=="+m.group());
            i++;
        }    
    }

}

控制台:

36
0==4==0==36==Twas
1==4==0==36==was
2==4==0==36==as
3==4==0==36==s
5==13==0==36==brilling
5==13==0==36==brilling
6==13==0==36==rilling
7==13==0==36==illing
8==13==0==36==lling
9==13==0==36==ling
10==13==0==36==ing
11==13==0==36==ng
12==13==0==36==g
14==17==0==36==and
14==17==0==36==and
15==17==0==36==nd
16==17==0==36==d
19==22==0==36==the
19==22==0==36==the
19==22==0==36==the
20==22==0==36==he
21==22==0==36==e
23==29==0==36==slithy
23==29==0==36==slithy
24==29==0==36==lithy
25==29==0==36==ithy
26==29==0==36==thy
27==29==0==36==hy
28==29==0==36==y
30==35==0==36==toves
30==35==0==36==toves
31==35==0==36==oves
32==35==0==36==ves
33==35==0==36==es
34==35==0==36==s

搜索的起点不断发生改变,每次从搜索起点位置开始去切出(group)那些寻找满足正则条件的子串。

猜你喜欢

转载自www.cnblogs.com/liudaihuablogs/p/9296465.html