黑马程序员--java基础之正则表达式

来源:互联网 发布:淘宝预热商品怎么删除 编辑:程序博客网 时间:2024/05/22 13:02
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

以前在公司上班的时候,因为工作上的需要,同事写了一个在网页上抓取数据的程序,然后放在公司的服务器,不停的运行,然后从别人的网站上抓取我们需要的数据,每隔3秒就访问一次网页,然后从新的网页上抓取数据。当时感觉很牛B,毕竟叫我弄,我是搞不定的,因为我不懂正则表达式。如今,咱也学习正则表达了,嘿嘿  大笑

咱们先来了解一下正则的知识

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

好处:可以简化对字符串的复杂操作。
弊端:符号定义越多,正则越长,阅读性越差。

以我们现阶段学习的知识来检验一个QQ号是否合格(不是以0开头,长度为5-15位的数字)
public static void checkQQ(){String qq="23414243";int len=qq.length();if(len>=5&&len<=15){if(!qq.startsWith("0")){char[] arr=qq.toCharArray();boolean flag=true;for(int x=0;x<arr.length;x++){if(!(arr[x]>='0' &&arr[x]<='9')){flag=false;break;}}if(flag){System.out.println("qq:"+qq);}else{System.out.println("qq号不符合规则");}}}}

从上面可以看出,仅仅是判断一个QQ号,用我们之前学习的知识来完成,要写一大堆的判断语句,非常麻烦。有没有简单的方法呢?duang  duang  duang  主角闪亮登场!!!!答案是有,它就是正则表达式!!!!!瞬间高大上了。。。。
用正则表达式如何做呢?
public static void method(){//不能以0开头,长度为5-15位的QQ号String str="1236465";String regex="[1-9]\\d{4,14}";boolean flag=str.matches(regex);System.out.println(flag);}

哇哦,屌爆了有没有!!!只有四句!!!哦,regex这个变量的值不懂?下面就来了。。。

字符x字符 x\\反斜线字符\0n带有八进制值 0 的字符 n (0 <= n <= 7)\0nn带有八进制值 0 的字符 nn (0 <= n <= 7)\0mnn带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)\xhh带有十六进制值 0x 的字符 hh\uhhhh带有十六进制值 0x 的字符 hhhh\t制表符 ('\u0009')\n新行(换行)符 ('\u000A')\r回车符 ('\u000D')\f换页符 ('\u000C')\a报警 (bell) 符 ('\u0007')\e转义符 ('\u001B')\cx对应于 x 的控制符 字符类[abc]abc(简单类)[^abc]任何字符,除了 abc(否定)[a-zA-Z]azAZ,两头的字母包括在内(范围)[a-d[m-p]]admp[a-dm-p](并集)[a-z&&[def]]def(交集)[a-z&&[^bc]]az,除了 bc[ad-z](减去)[a-z&&[^m-p]]az,而非 mp[a-lq-z](减去)

预定义字符类.任何字符(与行结束符可能匹配也可能不匹配)\d数字:[0-9]\D非数字: [^0-9]\s空白字符:[ \t\n\x0B\f\r]\S非空白字符:[^\s]\w单词字符:[a-zA-Z_0-9]\W非单词字符:[^\w] POSIX 字符类(仅 US-ASCII)\p{Lower}小写字母字符:[a-z]\p{Upper}大写字母字符:[A-Z]\p{ASCII}所有 ASCII:[\x00-\x7F]\p{Alpha}字母字符:[\p{Lower}\p{Upper}]\p{Digit}十进制数字:[0-9]\p{Alnum}字母数字字符:[\p{Alpha}\p{Digit}]\p{Punct}标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

再来看[1-9]\\d{4,14}:表示第一位是由1~9等数字组成。从第二位开始都是数字,而且数字的长度是4-14个,加上首位,长度就是5~15个了。。。



正则表达式具体操作功能

1、匹配 : String matches()    用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false 

/*匹配手机号,11位手机号段只有13xxx  15xxx  18xxx*/public static void method_1(){String tel="18707122014";String telReg="1[358]\\d{9}";System.out.println(tel.matches(telReg));}

2、切割    String[]  split(String regex) 

class RegexDemo{public static void main(String[] args){//使用.切割(单独的.代表任意字符,所以要加上转义字符,而在字符串中要使用转义字符要再加上\)method_Split("zhangsan.lisi.wangwu.sunba","\\.");method_Split("c:\\abc\\a.txt","\\\\");/*为了可以让规则的结果被重用,可以将规则封装成一个组,用()完成。组的出现 都有编号,从1开始,想要使用已有的组,可以通过\n (n就是组的编号)的形式来获取*///按叠词切(其中的小括号里的表示一组,后面的1表示后面的和第一组内容一致,.代表任意字符)method_Split("sdkkaseqqtryyfkaacgh","(.)\\1");//按多个叠词切()method_Split("sdkkaseqqqqqtryyyyyyyyyfkaacgh","(.)\\1+");}public static void method_Split(String str,String regex){String[] arr=str.split(regex);for(String s:arr){System.out.println(s);}}public static void method_Split1(){String str="zhangsan    lisi   wangwu zhaoliu";//切割多个空格String regex=" +";String[] arr=str.split(regex);for(String s:arr){System.out.println(s);}}}

以前,当我们遇到一个字符串由多个字符串组成,中间用一个空格隔开的时候,我们往往会通过split(" ")将这个字符串切割成一个字符串数组,但是当中间隔开的不是一个空格,而是多个空格时,我们就会抓狂了。。。。但是现在,可以用一个空格加一个"+"来表示多个空格,同样可以完成切割。是不是很方便?
当用于分隔的不是空格,而是小数点的时候,就用小数点分隔,但是,小数点在这里表示的是任意字符,而我们仅仅想把它作为小数点用,所以就用到了转义字符,而在字符串中,表示转义字符要用两个\\来表示。如上例
若是用\\隔开的咋办?那就是\\\\
注:为了可以让规则的结果被重用,可以将规则封装成一个组,用()完成。组的出现 都有编号,从1开始,想要使用已有的组,可以通过\n (n就是组的编号)的形式来获取。
"(.)\\1"  这个代表的意思是,()中的是一个组,代表的是任意字符,而后面的\\1表示使用编号为1的组的结果,并在一起就是两个相同的任意字符,就是叠词,"(.)\\1+",这里多了个"+"表示多个叠词



3、替换  String replaceAll()

class RegexDemo{public static void main(String[] args){//将字符串中长度大于等于5的数字替换成#method_Replace("asfdf13845218652asdfgkf23345aff","\\d{5,}","#");//将字符串中的叠词替换成"&"method_Replace("sdkkaseqqqqqtryyyyyyyyyfkaacgh","(.)\\1+","&");//将字符串中的叠词替换成一个,如zzz-->z //通过$来获取前一个规则中的第一个组method_Replace("sdkkaseqqqqqtryyyyyyyyyfkaacgh","(.)\\1+","$1");}//替换public static void method_Replace(String str,String reg,String newstr){str=str.replaceAll(reg,newstr);System.out.println(str);}}


正则表达式的第四个功能   
获取:将字符串中符合规则的子串取出

操作步骤:
1、将正则表达式封装成对象
2、让正则对象和要操作的字符相关联
3、关联后,获取正则匹配引擎
4、通过引擎对符合规则的子串进行操作。如取出

上面的步骤中涉及到了两个类  PatternMatcher

Pattern:正则表达式的编译表示形式。
Matcher:通过解释 Pattern 对 character sequence 执行匹配操作的引擎。通过调用模式的 matcher 方法从模式创建匹配器。

具体使用:
import java.util.regex.*;class RegexDemo2{public static void main(String[] args){getDemo();}public static void getDemo(){String str="ming tian jiu yao fang jia le ,da jia";System.out.println(str);/*其实String类中的matches方法。用的就是Pattern和Matcher对象来完成的。只不过被String的方法封装后,用起来较为简单。但是功能却单一。*///获取字符串中4个长度的单词//\b表示单词边际String reg="\\b[a-z]{4}\\b";//将规则封装成对象Pattern p=Pattern.compile(reg);//让正则对象和要作用的字符串相关联。获取匹配器对象Matcher m=p.matcher(str);/*类似于迭代器*///boolean b=m.find(); //将规则作用到字符串,并进行符合规则的子串查找//System.out.println(m.group());//用于获取匹配后结果。while(m.find()){System.out.println(m.group());System.out.println(m.start()+"...."+m.end());}}}
结果:


来两个练习:
/*练习到底用四种功能中的哪一个呢?或者哪几个呢?思路方式:1、如果只想知道该字符串是否对错,使用匹配2、想要将已有的字符串变成另一个字符串,替换3、想要按照自定的方式将字符串变成多个字符串,切割。获取规则以外的子串4、想要拿到符合需求的字符串子串,获取。获取符合规则的子串*/import java.util.*;class RegexTest1{public static void main(String[] args){Method_Test1();Method_Test2();checkMail();}/*需求:对邮件地址进行校验*/public static void checkMail(){    String mail="abc123@sina.com.cn";String reg="[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+"; //较为精确的匹配reg="\\w+@\\w+(\\.\\w+)+";//相对不太精确的匹配,因为  "1@1.1"也能匹配正确sop(mail.matches(reg));}/*192.168.1.254   102.49.23.013   10.10.10.10  2.2.2.2  8.109.90.30将IP地址进行地址段顺序的排序1、按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位。2、将每一段只保留3位。这样,所有的IP地址都是每一段3位*/public static void Method_Test2(){String ip="192.168.1.254   102.49.23.013   10.10.10.10  2.2.2.2  8.109.90.30";ip=ip.replaceAll("(\\d+)","00$1"); //补齐,使每一段至少3位sop(ip);ip=ip.replaceAll("0*(\\d{3})","$1"); //去掉多余的0,使每一段为3位sop(ip);String[] arr=ip.split(" +");  //将字符串转换为数据TreeSet<String> ts=new TreeSet<String>();for(String s:arr) //将数组中的元素添加到TreeSet集合中排序{ts.add(s);}for(String s:ts){sop(s.replaceAll("0*(\\d)","$1"));  //将每一段中多余的0去掉,如002-->2}}/*将下列字符串转成:我要学编程*/public static void Method_Test1(){String str="我我...我我...我想要...要要...要要...学学学...学学..编编编..编程..程.程程...程...程";/*将已有字符串变成另一个字符串,使用替换功能1、可以将.去掉2、再将多个重复的内容变成单个内容*/String reg1="\\.+";str=str.replaceAll(reg1,"");sop(str);String reg2="(.)\\1+";str=str.replaceAll(reg2,"$1");sop(str);}public static void sop(Object obj){System.out.println(obj);}}

应用:网页爬虫
旁白:妈呀,终于到正餐了,这个例子就是我开头说的,在网页上抓取数据的应用,来,咱也搞起。。。。

/*网页爬虫*/import java.io.*;import java.util.regex.*;import java.net.*;class RegexTest2{public static void main(String[] args) throws Exception{getMail() ;}public static void getMail() throws Exception{//数据源,从哪里抓取数据URL url=new URL("http://tieba.baidu.com/p/2986729518");  //从贴吧里一大堆求种的贴子里选了一个URLConnection urlconn=url.openConnection();//获取读取流BufferedReader brIn=new BufferedReader(new InputStreamReader(urlconn.getInputStream()));//将抓取的数据存入一个文件中BufferedWriter bwOut=new BufferedWriter(new FileWriter("mailList.txt"));String line=null;String mailReg="[a-zA-Z0-9]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";//将正则表达式封装成对象Pattern p=Pattern.compile(mailReg);while((line=brIn.readLine())!=null){//文本和引擎相关联Matcher m=p.matcher(line);while(m.find()){String str=m.group();bwOut.write(str);bwOut.newLine();bwOut.flush();System.out.println(str);}}}}

结果:     怎么样?  大笑

其实还有是有点瑕疵的,上面的截图只能截取部分,看一下文件吧

看到圈红线部分没,这部分肯定是有问题的,毕竟人家发的是QQ邮箱,但是最后截取的去含有字母。。。。。
我们可以在获取的结果里作下判断,如果结果字符串含有@qq,则从数字部分开始。。。但是也有问题,像uff0c开头的还好,后面的就是QQ号了,但是u5b50这样开始的就不好弄了。。。咋办?

看了下网页源代码:  实际上邮箱应该是选中部分,但是结果却是把前面的u300也截取过来了。。。各位看官,有什么方法没?(待续。。。)

0 0
原创粉丝点击