黑马程序员——自学总结(九)正则表达式

来源:互联网 发布:java pack 编辑:程序博客网 时间:2024/04/30 04:41

<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流!

一、概述

       正则表达式就是符合一定规则的字符串表达式。

       作用:专门用于操作字符串,使用原有字符串方法组合起来操作复杂数据代码量过大,而用正则表达式操作更便捷更简单。

       特点:用一些特定的字符来表示一些代码操作,这样简化了书写,所以学习正则表达式就是在学习一些特殊符号的使用。

       好处:可以简化对字符串的复杂操作。

       弊端:特定符号定义越多,正则表达式则越长,阅读性越差。

       需求:对QQ号码进行校验,要求:5-15位,0不能开头,只能是数字。

       以下是传统的字符串方法组合方式:

import java.io.*;class checkqq{public static Boolean check(String qq){int len=qq.length();if(len>=5 && len<=15){//判断长度                   if(!qq.startsWith("0")){//判断是否以0开头char[] c=qq.toCharArray();for(int i=0;i<len;i++)//对逐个字符进行判断if(!(c[i]>='0'&&c[i] <='9'))//有一个不是数字,则跳出循环,返回falsereturn false;return true;   }                   elsereturn false;}return false;            }public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String qq=null;try{while((qq=br.readLine())!=null){if("over".equals(qq))break;System.out.println(check(qq));}}catch(IOException e){throw new RuntimeException(e);}}}


 

可以对代码进行优化,检验是否为数字字符,可用Long.parseLong(qq),若抛出异常,则返回fasle,但代码量依旧过大。

使用正则表达式来判断:

import java.io.*;import java.util.regex.*;class checkqq{public static Boolean check(String qq){String regex="[1-9][0-9]{4,14}";return qq.matches(regex);}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String qq=null;try{while((qq=br.readLine())!=null){if("over".equals(qq))break;System.out.println(check(qq));}}catch(IOException e){throw new RuntimeException(e);}}}


 

简单、便捷。

二、正则表达式具体操作功能

        1、匹配

              String类有个matches(String regex)方法,用正则表达式regex匹配整个字符串,只要有一处不符合规则就匹配结束,返回false。

              在正则表达式中规定了如下几类字符:

              特殊字符类,比如\n换行符,\r回车符,\t制表符,\f换页符等

              字符类,比如[abc]表示某位字符为abc其中之一,[a-z]表示某位字符为a到z其中之一,'[^abc]表示某位字符为除了abc以外的字符, [a-d[n-p]]取并集,表示字符为a到d或n到p其中之一, [a-z&&[def]]取交集,表示字符为a到z,,且在def中,即def其中之一,[a-z&&[^bc]] ,表示a到z中除了bc以外的某一字符,[a-z&&[^n-p]]表示字符在a到z之中,但不在n到p之中,即字符在a到m或q到z中。

            预定义字符类,比如.任意字符,\d数字,\D非数字,\s空白字符(包括\t,\n,\x0B,\f,\r),\S非空白字符 ,\w单词字符,包括所有字母和数字,\W非单词字符。

            数量词,X?X出现一次或零次 ,X*零次或多次,X+一次或多次,X{n}恰好n次,X{n,}至少n次,X{n,m}至少n次,不超过m次。上例中QQ校验规则可以写成regex="[1-9]\\d[4,14]"。

练习:校验手机号码,匹配规则:手机号段只有13XXX 15XXX 18XXX 。

代码如下:

import java.io.*;import java.util.regex.*;class checkphonenumber{public static Boolean checkphonenumber(String qq){String regex="[1][358]\\d{9}";return qq.matches(regex);}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String qq=null;try{while((qq=br.readLine())!=null){if("over".equals(qq))break;System.out.println(checkphonenumber(qq));}}catch(IOException e){throw new RuntimeException(e);}}}


        2、切割

               String类中有一切割方法split(String regex),按指定的正则表达式规则切割字符串,下面演示将文件绝对路径中各个目录名和文件名切割出来:

              

import java.io.*;import java.util.regex.*;class mysplit{public static void mysplit(String path){String regex="\\\\";//java中"\\"表示字符'\',在正则表达式中则用"\\\\"匹配java字符串中的"\\"for(String s:path.split(regex))System.out.println(s);}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String path=null;try{while((path=br.readLine())!=null){if("over".equals(path))break;mysplit(path);}}catch(IOException e){throw new RuntimeException(e);}}}

程序运行结果如下:


 

          对字符串按叠词切割,例如"abckkdehhhfghcccccover”切割成"abc”,"de”,"fgh"和"over"。

 

import java.io.*;import java.util.regex.*;class mysplit{public static void mysplit(String s){String regex="(.)\\1+";for(String buff:s.split(regex))System.out.println(buff);}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String s=null;try{while((s=br.readLine())!=null){if("over".equals(s))break;mysplit(s);}}catch(IOException e){throw new RuntimeException(e);}}}


         为了可以让规则的结果被重用,可以将规则封装成组,用()完成,组的出现都有编号,从1开始,想要使用已有的组,可以通过\n的形式来获取,n就是组的编号。

        3、替换

              String类中的replaceAll(String regex,String s)可将符合规则的子串替换成指定字符串,可应用于比如论坛发帖时屏蔽掉手机号,QQ号。

            上例中, 将叠词全部换成单个字符,用“$1”获取前面规则的第1组。

import java.io.*;import java.util.regex.*;class myreplaceall{public static void myreplaceall(String s){s=s.replaceAll("(.)\\1+","$1");System.out.println(s);}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String s=null;try{while((s=br.readLine())!=null){if("over".equals(s))break;myreplaceall(s);}}catch(IOException e){throw new RuntimeException(e);}}}

        4、获取:将字符串中的符合规则的子串取出

              操作步骤:1、将正则表达式封装成对象,Pattern p=Pattern.compile(regex);2、让正则对象和要操作的字符串相关联;3、关联后,获取正则匹配引擎,Matcher m=p.matcher(str);4、通过引擎对符合规则的子串进行操作,比如取出。

              Pattern是正则表达式的编译表示形式,使用时需导包java.util.regex.*;Pattern类没有构造函数,有静态方法compile(regex)返回Pattern对象。String类中的matches方法,用的就是Pattern和Matcher对象来完成的,只不过被String的方法封装后,用起来较为简单,但是功能却单一。

             演示:将连续出现的3个相同字符取出,m.find()将规则作用到字符串上,并进行符合规则的子串查找,之后m.group()用于获取匹配后结果,类似于迭代器的功能。

            代码如下:

import java.io.*;import java.util.regex.*;class myget{public static void myget(String s){String regex="(.)\\1{2}";Pattern p=Pattern.compile(regex);Matcher m=p.matcher(s);while(m.find())System.out.println(m.group());}public static void main(String[] args){BufferedReader br=new BufferedReader(new InputStreamReader(System.in));String s=null;try{while((s=br.readLine())!=null){if("over".equals(s))break;myget(s);}}catch(IOException e){throw new RuntimeException(e);}}}


       m.start(),m.end()分别返回匹配结果起始索引位,和末尾索引位+1,同一比较器使用同一索引位,查找时比较器不断后移,下一次启动查找时接着上一次匹配后起开始查找。查找单词使用边界匹配器\b单词边界 \B非单词边界。

三、练习

        1、需求:将下列字符串转成:我要学编程

            “我我...我我...我要...要要...要要...学学学...学学...编编编...编程...程.程程...程...程”

              思路方式:(1)、如果只想知道该字符是否对错,使用匹配;(2)、想要将已有的字符串变成另一个字符串,替换;(3)、想要按照自定的方式将字符串变成多个字符串,切割;(4)、想要拿到符合需求的字符串子串,获取,获取符合规则的子串。

              代码如下:

import java.io.*;import java.util.regex.*;class myget{public static void main(String[] args){String s="我我...我我...我要...要要...要要...学学学...学学...编编编...编程...程.程程...程...程";//先把字符串中的...去掉s=s.replaceAll("\\.+","");//再去掉重复字符s=s.replaceAll("(.)\\1+","$1");System.out.println(s);}}


        2、需求:将下列IP地址192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2  8.109.90.30进行地址段顺序的排序。

              思路:按照字符串自然顺序,只要让它们每一段都是3位即可,(1)、按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位,(2)、将每一段只保留3位,这样所有的IP地址都是每一段3位。

              代码如下:

import java.io.*;import java.util.regex.*;import java.util.*;class myget{public static void main(String[] args){String[] s=new String[]{"192.68.1.254","102.49.23.013","10.10.10.10","2.2.2.2","8.109.90.30"};//因为字符串b赋给字符串a后,对a内容的修改将会使a指向另一个字符串,而原来的b内容没有改变,所以不//用迭代器。for(int i=0;i<s.length;i++){s[i]=s[i].replaceAll("(\\d+)","00$1");//先将每个IP都补上两个0s[i]=s[i].replaceAll("0*(\\d{3})","$1");//将后3位数字保留}Arrays.sort(s);//排序for(String buff:s)System.out.println(buff);}}


 

              练习:需求:对邮件地址进行校验,较为精确的匹配,正则表达式为"[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}"相对不太精确的匹配,正则表达式为"\\w+@\\w+(\\.\\w+)+"。

四、网页爬虫

        网页爬虫用于获取指定文档中的邮件地址,使用Pattern对象和Matcher对象。

0 0