• 第十三章 字符串 正则匹配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 " + "Did gyre and gimble in the wabe. "; 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()只有在正则表达式与输入的最开始处就开始匹配时才会成功。
     * matches只有在整个输入都匹配正则表达式时才会成功,而lookingAt()只要输入的第一部分匹配就会成功
     * 找出所有不以大写字母开头的词,不重复的计算其个数
     * @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
    " +
            "Did gyre and gimble in the wabe.
    ";
            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
    ";
            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)那些满足正则条件的子串。

    Matcher.lookingAt()只要输入的第一部分匹配就会成功【从头开始寻找,只要能找到一个满足正则匹配的子串就返回true】:

    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 s1 = "Twas brilling,and  the slithy toves
    ";
            String s2 = " Twas brilling,and  the slithy toves
    ";
            String s3 = "T;was brilling,and  the slithy toves
    ";
            Pattern pattern = Pattern.compile("\w+");
            Matcher m1 = pattern.matcher(s1);
            Matcher m2= pattern.matcher(s2);
            Matcher m3= pattern.matcher(s3);
            
            System.out.println(m1.lookingAt()+"="+m1.start()+"="+m1.end()+"="+m1.group());
            System.out.println(m2.lookingAt());
            //没找到,当调用start/end/group时会抛出异常
            //System.out.println(m2.start()+"="+m2.end()+"="+m2.group());
            System.out.println(m3.lookingAt()+"="+m3.start()+"="+m3.end()+"="+m3.group());;
        }
    
    }

    控制台:

    true=0=4=Twas
    false
    true=0=1=T

    从头开始寻找,只有找到一个满足正则匹配的表达式就返回true,s1找到的字符串为Twas,s2首先第一个字符就不满足正则匹配,直接返回false,s3找到的字符串为T

     

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    洛谷P2661: 信息传递(图的遍历)
    洛谷P1305: 新二叉树
    洛谷 P1030 :求先序排列
    POJ 3041:Asteroids(二分图最大匹配)
    洛谷P2774 :方格取数问题( 网络流24题 奇偶建图+最小割)
    hdu 3061:Battle(最大权闭合图)
    hdu 1532:Drainage Ditches(Dinic算法)
    洛谷P1345: [USACO5.4]奶牛的电信Telecowmunication(拆点+最小割)
    hihoCoder1121 : 二分图一•二分图判定
    (转载)javascript客户端生成MD5值的函数代码
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/9296465.html
Copyright © 2020-2023  润新知