黑马程序员--正则表达式

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-
正则表达式:符合一定规则的表达式。

作用:专门用于操作字符串。
特点:用一些特定的符号来表示一些代码操作。这样就简化书写。
好处:可以简化对字符串的复杂操作。
      所以学习正则表达式,就是在学习一些符号的使用
弊端:符号定义越多,正则越长,阅读性越差

String 类中提供的方法较简单,组合起来操作代码麻烦,
正则表达式是对字符串即便捷又简单的操作方法。

下面通过一个小例子来体现以下正则表达式。

/*
需求: 
对QQ号码进行校验,要求5-15位,0不能开头,只能是数字           
*/
class CheckQQDemo 
{
    public static void main(String[] args) 
    {
        //method_1("1254444454635555");
        method("23434d5555");
    }

    //使用正则表达式
    public static void method_1(String qq)
    {
        String regex="[1-9][0-9]{4,14}";
        boolean flag=qq.matches(regex);
        if(flag)
            System.out.println(qq+"..is ok");
        else
            System.out.println(qq+".....no OK");
    }

    //不使用正则表达式
    //这种方式使用了String类中的方法进行组合完成需求,但是代码过于复杂
    public static void method(String qq){
        int len=qq.length();
        if(len>=5&&len<=15)
        {
            if (!qq.startsWith("0"))
            {
                try
                {
                    long l=Long.parseLong(qq);
                    System.out.println("qq:"+qq);
                }
                catch (NumberFormatException e)
                {
                    System.out.println("出现非法字符");
                }

                /*
                char[] arr=qq.toCharArray();
                boolean flag=false;
                for (int i=0; i<arr.length; i++)
                {
                    if(!(arr[i]>'0'&&arr[i]<='9'))
                    {
                        flag=true;
                        break;
                    }
                }
                if(!flag)
                {
                    System.out.println("qq:"+qq);
                }
                else
                {
                    System.out.println("出现非法字符");
                }
                */
            }
            else
            {
                System.out.println("不可以0开头!");
            }
        }
        else
        {
            System.out.println("长度错误");
        }
    }
}

通过上面的示例可以看出正则表达式,极大地简化了书写,让操作变得很方便。

正则表达式中常用的一些特殊符号:
字符类符号

    [abc]可以判断一个字符串当中某一个字符位上出现的字符,a或b或c
    eg:a.matcheds("[bcd]"); 返回的是false。
    [a-zA-Z]
    [^abc]
    [a-d[m-p]]a到d或m到p去交集
预定义字符:
    .    任意字符
    \d   任意数字 使用时 \\d
            注意在正则表达式中\\总是成对出现
    \D   任意非数字
    \s   空白字符[\t\n\0B\f\r]
    \S   非空白字符
    \w   单词字符[a-zA-Z_0-9]  邮箱校验
    \W   非单词字符
数量词:
    X?       X,一次或一次也没有 
    X*       X,零次或多次 
    X+       X,一次或多次 
    X{n}     X,恰好 n 次 
    X{n,}    X,至少 n 次 
    X{n,m}   X,至少 n 次,但是不超过 m 次 
边界匹配器 
    ^ 行的开头 
    $ 行的结尾 
    \b 单词边界 
    \B 非单词边界 
    \A 输入的开头 
    \G 上一个匹配的结尾 
    \Z 输入的结尾,仅用于最后的结束符(如果有的话) 
    \z 输入的结尾 

正则表达式对字符串的具体操作:
1.匹配
boolean matches()方法。用规则匹配整个字符串,只要有一处不符合,就返回false
eg:
QQ匹配:[1-9]\d{4-14}
匹配手机号码:
要求:手机号段只有13***,15***,18***
手机号码匹配正则:1[358]\d{9}
2.切割
String[] split(String regex)

    public static void splitDemo()
    {   
        /*
        String str="zhangsan   lisi     wangwu zhaoliu    heh";
        String reg=" +";//按照多个空格进行切割
        */
        /*
        String str="zhangsan.lisi.wangwu.zhaoliu.heh";
        //String reg=".";//.是正则表达式中的符号,直接用.切出错
                        //想使用.必须先将.转义,给.转义的\也是正则表达式中的符号,所以需要把\也转义,即\\.
        String reg="\\.";
        */
        /*
        String str="C:\\abc\\a.txt";
        String reg="\\\\";//很特殊的部分,使用时一定要小心
        */
        //按照叠词切
        String str="erkkbfdffdkkd"; 
        String reg="(.)\\1";
        String[] arr=str.split(reg);
        for (String s: arr)
        {
            System.out.println(s);
        }
    }

按照叠词切String str=”erkkbfdffdkkd”;
String regex=”“;
该怎么切呢?

这就涉及到了组的概念。
把要重用的部分用(.)括起来,通过\n的形式来捕获组"(.)\\1"
重用的部分超过2次"(.)\\1+"
为了让规则的结果被重用可以将规则封装成一个组。用()完成。
组的出现都有编号,从1开始。想要使用已有的组可以通过\n(n就是组的编号)的形式来获取

((())())   看有几组可以数()的个数,有几个()就有几组
组的出现就体现出来了正则表达式的弊端:阅读性极差

3.替换
replaceAll(String regex,String replacement)

    public static void replaceAllDemo()
    {
        //模拟发帖子中带有qq账号信息,将带有的qq信息替换成#
        /*
        String str="wer1235555dd488488494654dfdfdg";
        String reg="\\d{5,}";
        str=str.replaceAll(reg,"#");
        */
        /*
        //将叠词替换成&
        String str="erkkbfdffdkkkkkkd";
        String reg="(.)\\1+";
        str=str.replaceAll(reg,"&");
        */
        //将叠词替换成单个字符kk-->k   zzzz-->z
        String str="erkkbfzzzzdffdkkkkkkd";
        String reg="(.)\\1+";
        //★★★特殊
        str=str.replaceAll(reg,"$1");//可以通过$获取前一个规则中的组
        System.out.println(str);
    }
}

4.获取 按照规则把符合规则的子串取出
操作步骤:

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

与获取操作有关的类:
Pattern 该类无构造函数,根据经验该类会提供静态方法返回本类对象。
Pattern.compile(String regex);
Matcher 很吊的一个类,里面提供了各种方法

import java.util.regex.*;
class RegexDemo 
{
    public static void main(String[] args) 
    {
        getDemo();
    }

    public static void getDemo()
    {
        //需求将字符串中连续三个字母的子串取出    eg:取出jiu  yao  jia
        String str="ming tian jiu yao fang jia le";

        //String regex="\\w{4}";//单词有边界,这里需要使用单词边界匹配

        String regex="\\b\\w{4}\\b";
        //1.将规则封装成对象
        Pattern p=Pattern.compile(regex);

        //2.让正则对象和要操作的字符串相关联。获取匹配器对象。
        Matcher m=p.matcher(str);
        /*
        学习到这里可以看出,String类中的matcher方法用的就是
        Pattern和Matcher中的matcher方法,只不过是String类把
        这些方法封装在了内部,用起来较为简单,但是功能单一,
        想要使用更多复杂功能,就要回来找Pattern和Matcher类。
        */
        /*
        boolean b=m.find();//将规则作用到字符串上,并进行复核规则的子串查找

        System.out.println(b);

        System.out.println(m.group());//获取匹配结果
        */

        //System.out.println(m.matches());
        //一个小细节:如果下面的代码前面加上上面的这句m.matches(),
        //则输出结果会有可能发生错误,ming没有输出,这是因为一个匹
        //配引擎内部使用的是同一个角标,而matches()方法作用于整个字
        //符串,当匹配结束返回false,角标已经到了tian的t的位置,因
        //此,调用find()方法,角标是从t的位置开始的,结果中就少了个ming。 
        //使用时一定要注意。
        while(m.find())
        {
            System.out.println(m.group());
        }
    }
}

正则表达式解决问题比较通用的思考方式:

1.如果只想知道该字符串是对是错,匹配。
2.想要将已有的变为另一个字符串,替换。
3.想要按照自定的方式将字符串变成多个字符串,切割。获取规则以外的子串
4.想要拿到符合需求的字符串子串,获取。 获取符合规则的子串

两个关于正则的小练习:

import java.util.*;
class RegexTest 
{
    public static void main(String[] args) 
    {
        //ipSort();
        checkMail();
    }
    /*
        练习:将ip地址按照ip地址段顺序排序
        192.168.1.254 102.49.23.013 10.10.10.10 2.2.2.88 8.109.55.90
        升序排序
        思路:
        还按照字符串自然顺序排列,只要让他们每一段三位即可
        1.按照每一段需要的最多的0进行补齐,那么每一段就会至少保证三位。
        2.将每一段只保留3位,这样,所有ip地址都是每一段三位
    */
    public static void ipSort()
    {
        String ip="192.168.1.254 102.49.23.013 10.10.10.10 2.2.2.88 8.109.55.90";   
        ip=ip.replaceAll("(\\d+)","00$1");
        System.out.println(ip);
        ip=ip.replaceAll("0*(\\d{3})","$1");
        System.out.println(ip);

        String[] arr=ip.split(" +");
        TreeSet<String> ts=new TreeSet<String>();
        for (String s: arr)
        {
            ts.add(s);
        }

        for(String s:ts)
        {
            System.out.println(s.replaceAll("0*(\\d+)","$1"));
        }
    }

    /*
        对邮箱校验
    */
    public static void checkMail()
    {
        String mail="avbdgf@sina.com.cn.hah.hgh";
        //@前边固定,后边不固定

                    //可以有下划线 没下划线      没数字下划线
        String regex="\\w{6,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}";//较为精准的匹配
        System.out.println(mail.matches(regex));

        //regex="\\w+@\\w+(\\.\\w+)+";//相对不太精准的匹配
        /*
            mail.indexOf("@")!=-1  //建立在大部分人都对邮箱格式熟知的基础上
        */
    }
}   

网页爬虫:

import java.io.*;
import java.net.*;
import java.util.regex.*;
class RegexTest3 
{
    public static void main(String[] args) throws Exception
    {
        //getMailsByIE();
        getMails();
    }

    /*
        获取指定文档中的邮件地址
        包含获取操作,需要用到Pattern和Matcher类
    */
    public static void getMails()throws Exception
    {
        BufferedReader bufr=new BufferedReader(new FileReader("mail.txt"));

        Pattern p= Pattern.compile("\\w{5,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}");

        String line=null;

        PrintWriter out=new PrintWriter(new FileOutputStream("mailgeted.txt"),true);

        while ((line=bufr.readLine())!=null)
        {
            Matcher m=p.matcher(line);
            while(m.find())
            {
                out.println(m.group());
                //System.out.println(m.group());
            }
        }
        out.close();
        bufr.close();
    }
    /*将网页中获取的邮箱地址存入文件中*/
    public static void getMailsByIE()throws Exception
    {
                //百度贴吧上找了个带回复中有邮箱的网址    
        URL url=new URL("http://tieba.baidu.com/p/2314539885");
        URLConnection uc=url.openConnection();
        BufferedReader bufr=new BufferedReader(new InputStreamReader(uc.getInputStream()));
        Pattern p= Pattern.compile("\\w{5,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}");

        String line=null;
        PrintWriter out=new PrintWriter(new FileOutputStream("mailgeted_1.txt"),true);
        while ((line=bufr.readLine())!=null)
        {
            Matcher m=p.matcher(line);
            while(m.find())
            {
                //System.out.println(m.group());
                out.println(m.group());
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值