day25_正则表达式(match,split,get,replace)

 

1.正则表达式概述:

/*
正则表达式:
   符合一定规则的表达式
   作用:用于专门操作字符串
   特点:可以简化对字符串的复杂操作
   优点:用于一些特定的符号来表示一些代码操作.这样就简化书写
   缺点:符号定义越多,正则越多,阅读性极差
四大功能:
  1.如果想知道该字符串是否满足要求->匹配:matches/Matcher
  2.想要将已有的字符串变成另一个字符串->替换:reaplaceAll
  3.想要按照自定的方式将字符串变成多个字符串->切割,获取规则以外的子串:split
  4.想要拿到符合需要的字符串子串,获取.获取符合规则的子串:Pattern,Matcher
*/

2.匹配:

匹配符合规则的QQ,未使用正则与使用正则对比:

package regex;
class RegexDemo{
    /*
    检测QQ的合法性:
    1.5~15位
    2.不能以0开头
    3.只能是数字
    */
   public static boolean checkQQ(String QQ){
      if(!(QQ.length()>=5 && QQ.length()<=15))
          return false;//满足以上条件,直接返回
      else
         if(QQ.startsWith("0"))
            return false;
         else{
           char[] arr=QQ.toCharArray();
           for(char ch : arr)
            if(!(ch>='0'&& ch<='9'))
               return false;
           return true;//能够走到这一步说明数组中元素都符合要求
         }
        
         /*
         //或者使用: 
           try{
             int qq=Integer.parseInt(QQ);
           }
           catch(NumberFormatException e){
             return false;
           }
           return true;
         */
         
   
   }
   /*利用正则表达式检测*/
   public static boolean regexCheckQQ(String QQ){
       String regex="[1-9][0-9]{4,14}";//第一位1~9,第二位0~9,出现了4~14次
       return QQ.matches(regex);// boolean matches(String regex) 
                               //告知此字符串是否匹配给定的正则表达式。 
   }
   public static void main(String[] args){
      if(checkQQ(args[0]))
          System.out.println(args[0]+"合法");
      else
          System.out.println(args[0]+"非法");
      
      
      
      if(regexCheckQQ(args[0]))
        System.out.println(args[0]+"合法");       
      else
         System.out.println(args[0]+"非法");

   }
}
/*
由此看出:
第一种方法是String类中的方法的组合,代码过于复杂,没有使用
正则表达式简单
*/
/*
    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]          a或b 或 c(简单类) 
    [^abc]         任何字符,除了 a、b 或 c(否定) 
    [a-zA-Z]       a 到 z 或 A 到 Z,两头的字母包括在内(范围) 
    [a-d[m-p]]     a 到 d 或 m 到 p:[a-dm-p](并集) 
    [a-z&&[def]]   d、e 或 f(交集) 
    [a-z&&[^bc]]   a 到 z,除了 b 和 c:[ad-z](减去) 
    [a-z&&[^m-p]]  a 到 z,而非 m 到 p:[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]
    注意:java中\后跟的字符会被转义,例如:如果想使用\d->\\d(使\做为普通字符)
   Greedy 数量词 
        X?         X,一次或一次也没有 例如:"[a-zA-Z]\\d?":第二位是数字,出现一次或者一次没有
        X*            X,零次或多次       例如:"[a-zA-Z]\\d*":第二位是数字,数字出现0~多次.
        X+         X,一次或多次       
        X{n}       X,恰好 n 次 
        X{n,}       X,至少 n 次 
        X{n,m}       X,至少 n 次,但是不超过 m 次 例如:QQ:"[1-9]\\d{4,14}"
        */

匹配示例:

//使用规则匹配整个字符串:String中的matches方法,在匹配过程中一旦发生不匹配,返回false
class RegexDemo2{
  
  public static void demo(){
    String str="a";
    String regex="[bcd]";//字符串只能有一个字符,字符串中的第一个字符只能是b或c或d
    System.out.println(str.mathes("[bcd]"));
  }
  public static void main(String[] args){
         demo()
  }


}
/*
手机号段:
 13***,15***,18*** (共11位)
 regex:"1[358]\\d{9}"
*/

3.切割与替换:

package regex;
import java.util.Arrays;
class RegexDemo3{
  public static void splitResult(String str,String regex){
    String[] split=str.split(regex);
    System.out.println(split.length);
    for( String s : split)
        System.out.println(s);
    System.out.println();
  }
  
  public static void splitDemo(){
    String str="zhangsan  wangwu      lisi";
    String regex=" +";//zhangsan,wangwu之间可能出现一次或多次空格
    splitResult(str,regex);
    
    str="zhangsan.wangwu.lisi";
    regex="\\.";//想按照.切割,在正则表达式中.代表任意字符(有特殊含义)
             //因此在正则中\.转义,但是又产生个问题,java中\.没有这个转义字符(报错:非法的转义字符,就好像\n:换行,\.没有特殊含义)
             //那么在使\做为普通字符,\\-->\\.
    splitResult(str,regex);
 
    
    
    str="c:\\abc\\1.txt";
    regex="\\\\";
//
相当于两个普通的'\'
    splitResult(str,regex);


    str="erkktyqqquizzzzzo";
    regex="(.)\\1+";          //+:出现一次或多次,也可以使用{1,}                  
    splitResult(str,regex);     //按照叠词切割,为了可以让规则的结果被重用
                            //可以将规则封装成一个组,用()完成.组的出现都有编号
                            //从1开始.想要使用(捕获)已有的组可以通过\n(n就是组的编号)形式获取
                            //((A)(B(C))):4组,看组的个数从左括号的个数入手,并且从左到右依次编号:1组,2组...... 

    
    
  }


  /*替换*/
  public static void replaceAllDemo(){
   String str="wer13899800000ty1234564uiod234uiod234345675f";//将字符串中连续5个或5个以上的数字替换成#
   String regex="\\d{5,}";
   String newStr="#";
   System.out.println(str.replaceAll(regex,newStr));

   str="erkktyqqquizzzzzo";//将叠词替换成&
   regex="(.)\\1+";
   newStr="&";
   System.out.println(str.replaceAll(regex,newStr));

   
   regex="(.)\\1+";//将叠词替换成单个字母:kk->k,qqq->q....
   newStr="$1";//由于后面替换需要根据正则中的'.'来决定,获取上面regex中的第一组
   System.out.println(str.replaceAll(regex,newStr));
   
   
   newStr="$";//把叠词替换成$
   System.out.println(str.replaceAll(regex,newStr));//Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1
                                                    //这是因为$在正则中为特殊符号,IndexOutOfBoundsException - 如果替换字符  串引用模式中不存在的捕获组。
  }                                                 //可以用"\\$"替换;
  
  
  public static void main(String[] args){
         splitDemo();
         System.out.println();
         replaceAllDemo();
  }


}

Split Replace

4.获取:

/*
正则表达式:
   4.获取功能:将字符串中符合规则的字串取出
操作步骤:
  1.将正则表达式封装成对象.
  2.让正则对象和要操作的字符串相关联
  3.关联后,获取正则匹配引擎
  4.通过引擎对符合规则的子串进行操作,比如取出
*/
package regex;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class RegexDemo4{
    public static void getDemo(String str,String regex){
      
      //将规则封装成对象
       Pattern p=Pattern.compile(regex);
      //让正则对象和要操作的字符串相关联,获取匹配器对象
       Matcher m=p.matcher(str);//Matcher 通过解释 Pattern 对 character sequence 执行匹配操作的引擎。 
      
      
      
      //System.out.println(m.group());//IllegalStateException - 如果没有尝试任何匹配,或者以前的匹配操作失败
                                   //异常原因:只获取到了匹配器对象,而没有进行匹配查找动作,因此没有结果
                                   //返回值:以前匹配操作所匹配的字符串形式的子序列(可能为空)。 
      
     
      /*
      m.find();//尝试查找与该模式匹配的输入序列的下一个子序列。
               //当且仅当 输入序列的子序列(子串) 匹配此匹配器的模式(正则表达式) 时才返回 true
      System.out.println(m.group()+"\n");//返回第一次匹配的子串
      */
      
      
      while(m.find()){//类比Iterator,每调用一次find都从上个以匹配的子序列的下个位置开始
        System.out.println(m.group());//jiu you //将会找出满足[a-z]{3}所有子串
        System.out.println(m.start()+"..."+m.end());//输出当前匹配子串的起始位置(0开始)和结尾位置(包含头不包含尾)
      }
    }
    public static void main(String[] args){
     
      getDemo("ming tian jiu you ","[a-z]{3}");
      System.out.println();
      
      //regex="\\b[a-z]{3}\\b";//\b 边界匹配器,单词的边界
      getDemo("ming tian jiu you ","\\b[a-z]{3}\\b");
    }
}

获取子串

注意:

/*
 
       //分析以下结果:
       String str="ming tian jiu you ";
       String regex="\\b[a-z]{4}\\b";
       Pattern p=Pattern.compile(regex);
       Matcher m=p.matcher(str);
       System.out.println(m.matches());//返回false,mathes会将整个字符串与模式匹配
                                       //对于:\\b[a-z]{4}\\b 该规则限定长度为4的字符串,因此不匹配
       
       while(m.find())//如果使用\\b[a-z]{4}\\b规则匹配
        System.out.println(m.group());//理应结果是ming tian
                                      //但是只有tian,这是因为在调用m.mathes后,匹配失败,内部指针已指到t位置,从该位置在开始匹配

*/

 

/*
转自:http://hi.baidu.com/bpy838/item/2eff9191500408f029164744(略有删改)

单词边界深入讨论:
1.到底什么是单词边界?
 单词字符:\w 单词字符:[a-zA-Z_0-9]:a~z 或 A~Z 或 下划线 或 0~9 
    
 元字符<<\b>>也是一种对位置进行匹配的“锚”。这种匹配是0长度匹配。有4种位置被认为是“单词边界”:
1)在字符串的第一个字符前的位置(如果字符串的第一个字符是一个“单词字符”)  例如:"Txxxxxx",T前的void匹配边界
2)在字符串的最后一个字符后的位置(如果字符串的最后一个字符是一个“单词字符”)例如:"xxxxxm",m后的void匹配边界
3)在一个“单词字符”和“非单词字符”之间,其中“非单词字符”紧跟在“单词字符”之后 例如:"A bxxxx",A和空格之间认为匹配\b,然后从空格开始匹配
4)在一个“非单词字符”和“单词字符”之间,其中“单词字符”紧跟在“非单词字符”后面 例如:" Asxxxxx",空格和A之间匹配\b,然后从A开始匹配

例:This island is beautiful  正则表达式:\bis\b
1.T前void匹配\b,T不匹配i,失败
2.一直匹配,直到第四个s和空格之间匹配\b,空格不匹配i,失败
3.第五个空格和后面的i之间匹配\b,i匹配i,s匹配s,但是s后l不匹配\b,失败
4.一直匹配,直到d和空格之间匹配\b,空格不匹配i,失败
5.空格和i之间匹配\b,i匹配i,s匹配s,s和空格之间匹配\b,成功->is
接下来的步骤同理.
*/

5.正则练习:

package regex;
import java.util.Arrays;
class RegexTest{
    public static void main(String[] args){

      replaceAll();
      System.out.println();
      IPSplit();
       System.out.println();
      emailMatch();
    }
    public static void replaceAll(){
        
     String str="我我...我我...我要...要要...学学学...学学...编编编...编程..程.程程...程...程";//转换为"我要学编程"
     String regex="\\.+";
     String newStr=str.replaceAll(regex,"");
     System.out.println(newStr);
     regex="(.)\\1+";
     System.out.println(newStr.replaceAll(regex,"$1"));
    
    }
    /*
     192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30
     将ip地址进行地址段顺序的排序.
    */
    public static void IPSplit(){
      //1.将每一段前面统一补两个零
       String ip="192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
       System.out.println((ip=ip.replaceAll("(\\d+)","00$1")));
      //2.将每一段替换成该段后三位:
       System.out.println((ip=ip.replaceAll("0*(\\d{3})","$1")));//对于002,相当于0出现零次,002为数字出现3次
      //3.把每一个IP地址切割出来
       String[] ipArr=ip.split(" +");
      //4.按照字符的ASCII码从小到大排序(TreeSet/Arrays.sort/Collections.sort)
       Arrays.sort(ipArr);
       for(String s : ipArr)
           System.out.println(s.replaceAll("0*(\\d+)","$1"));//5.需要把每一段多余的零去掉
    }

    public static void emailMatch(){
     /*
     邮箱匹配:
              abc12@sina.com
              abc_45@mab.com.cn
              abc_44@163.com
              abc34@sina.edu.com.cn
 
     */
     //精确匹配:
     String email="abc_45@mab.com.cn";
     String regex="[a-zA-Z_0-9]{6,}@[a-zA-Z0-9]+(\\.[a-zA-Z]{2,3}){1,3}";//有些对用户名有位数具体要求6~12位等等
                                                                    //(\\.[a-zA-Z]+){1,3} ->.edu.com.cn
     System.out.println(email.matches(regex));                  
     


     // email="abcdefghk";
     // regex="([a-z])+";
    // System.out.println(email.replaceAll(regex,"00$1"));//测试结果00k,$1代表最后一个匹配的值:k
    }
}

Test

6.网页爬虫:

/*
网页爬虫:根据需要获取(爬)网页信息

*/
package regex;
import java.io.*;
import java.util.regex.*;
import java.net.*;
class Siders{
  public static void getFromHtml()throws Exception{
   URL url=new URL("http://127.0.0.1:8080/myweb/mail.html");//假设mail.html含有邮箱地址,mail.html放到Tomcat下的webapps/myweb文件夹下
   URLConnection urlConn=url.openConnection();//连接成功需要开启Tomcat服务器
   BufferedReader bufIn=new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
   String line=null;
   String regex="\\w+@\\w+(\\.\\w+)+";//这里采用了非精确匹配
   Pattern p=Pattern.compile(regex);
    while((line=bufIn.readLine())!=null){
       Matcher m=p.matcher(line);
       while(m.find())
           System.out.println(m.group());
   }
  } 
  public static void main(String[] args)throws Exception{
  
  
    getFromHtml();
  }
}
/*获取文件中需要信息原理同上*/

mali.html中的邮箱前后带有空格,这是正则表达式不精确缘故

email

posted @ 2013-07-16 10:40  伊秋  阅读(522)  评论(0编辑  收藏  举报