概念:
正则表达式:即符合一定规则的表达式
作用:专门用于操作字符串
特点:用一些特定的符号来替代一些代码操作,简化书写
学习正则表达式就是在学习指定其规则的符号的使用,即如何定义规则,详细方法参见API文档Pattern中正则表达式的规则组成
优点:简化字符串操作步骤
弊端:符号定义多时,正则越长,阅读性越差
具体操作功能:
1,匹配:String matches()方法;设定regex规则,只要有一处不匹配,就返回false2,切割:String split()方法就是 将regex作为参数传入,可以定义regex实现复杂的切割
3,替换:String replaceAll()方法
class RegexDemo { public static void main(String[] args) { // checkQQ_1();String类传统方法 //一、匹配 qq号验证 // checkQQ_2("667788","[1-9][0-9]{4,9}");定义规则:[0-9]首位1~9;[0-9]{4,9}其它位为数字,出现次数范围 //手机号验证 // checkTel("18688888888","1[358]\d{9}");定义规则首位1,第二位为3/5/8,后面9位数字,正则表达式的构造字符d要加转义字符 //二、切割 // splitDemo("zhangsan lisi wangwu"," +");//一个或多空格切割 //"."切割 // splitDemo("zhangsan.lisi.wangwu","\.");//"."表示任意字符;"."表示正则表达式中的".",前面要加转义字符>>"\." //双"\"切割 // splitDemo("d:\java\demo.java","\\");//四个"\\"来表示两个\;因为要加转义 // 按照叠词切割;"组"的概念 // splitDemo("hssbkkdaa","(.)\1+");//规则:叠词重复一次或多次 //三、替换 String str = "tel:18688886666QQ22876686MM548434";//将字符串中数字替换成# replaceAllDemo(str,"\d{5,}","#");//规则:数字,出现5次以上 String str2 = "hdsdsdddggvmmmop";//将叠词替换成单个字母(ddd>>d) replaceAllDemo(str2,"(.)\1+","$1"); } public static void replaceAllDemo(String str, String reg, String newStr ){ str = str.replaceAll(reg,newStr); //String类方法,正则表达式的复杂替换 System.out.println(str); } public static void splitDemo(String str, String reg){ String[] arr = str.split(reg);//根据规则来切割 System.out.println(arr.length); for (String s : arr ) { System.out.println(s); } } //匹配手机号:只是能以13 15 18 开头的11位数字 public static void checkTel(String tel, String telReg){ //匹配 System.out.println(tel.matches(telReg)); } public static void checkQQ_2(String qq, String regex) //二、String类的matches方法 { boolean flag = qq.matches(regex); //判断输入的qq与规则是否匹配,返回值为boolean型 if (flag) System.out.println("QQ: "+qq); else System.out.println("QQ号有误,请重新输入!"); } public static void checkQQ_1()//一、使用String类中方法组合完成需求,比较复杂 { String qq = "286345"; int len = qq.length(); if (len>=5 && len<=10) //1,号码长度 { if (!(qq.startsWith("0")))//2,String类方法,判断字符串是否以0开头 { try { long l = Long.parseLong(qq);//将数字字符串转成数字 System.out.println("QQ: "+qq); } catch (NumberFormatException e)//会如果不是纯数字字符串,会抛出数字转换异常 { System.out.println("QQ号为0~9的数字"); } /* char[] arr = qq.toCharArray();//将字符串转成字节数组 boolean flag = true;//设置标记 for (int x=0; x<arr.length; x++ ){ if (! (arr[x]>='0' && arr[x]<='9')){//3,判断字符数组是否为数字字符 flag = false; break; } } if (flag){ System.out.println("QQ: "+qq); } else{ } */ System.out.println("QQ号为0~9的数字");//3, } else{ System.out.println("不能以0开头");//2, } } else{ System.out.println("号码长度为5~10位"); //1, } } }
使用String类中方法组合完成需求,比较复杂,使用正则表达式,用“符号”替换代码,可以大大简化书写
组的概念:
按照叠词完成切割,为了可以让叠词的结果可以被重用,可以将规则用()封装成一个组,组的出现都有编号
(编号n)
想要使用已有的组可以通过
的形式来获取;有几个()就有几个组
正则表达式第四个功能:获取
将字符串中符合规则的子串取出;切割得到的是规则以外的,获取得到的是符合规则的
操作步骤:
1,将正则表达式封装成对象
2,将正则对象和要操作的字符串相关联
3,获取正则匹配引擎
4,通过引擎对符合规则的子串进行操作,如取出
获取涉及到两个类对象:
Pattern类和Matcher类
Pattern类没有构造方法
通过其compile()方法将正则封装成对象
通过其matcher()方法获取匹配引擎,返回此模式的新匹配器
matcher();将正则对象和要操作的字符串相关联,获取匹配器对象
charSequence接口,字符序列
要分清楚matcher()方法与matches()方法的区别,前者返回对象,后者返回boolean
Matcher类,匹配器
方法:
find();find方法将规则作用到字符串上,进行符合规则的子串查找
group();group方法获取匹配结果
import java.util.regex.*; class RegexDemo2 { public static void main(String[] args) { getDemo(); } public static void getDemo() { String str = "jin tian hui jia le ,haha. "; String reg = "\b[a-z]{3}\b"; //\b表示字符边界 Pattern p = Pattern.compile(reg);//将正则封装成对象 Matcher m = p.matcher(str); //将正则对象和要操作的字符串相关联,获取匹配器对象 // System.out.println("Matcher: "+m.matches());// while (m.find())//find方法将规则作用到字符串上,进行符合规则的子串查找 { System.out.println(m.group());//group方法获取匹配结果 } } }
运行结果:
如:在获取之前先对该字符串进行判断,获取位置就会从该判断结束的位置开始
运行结果如图:
分析:规则为三个字符,方法natcher判断"jin"之后返回false,此时索引停留在“tian"上,下面的fand()方法就从"tian"开始查找;所以就获取不到“jin”
正则表达式的操作思路:
1,如果只想知道该字符是否符合标准,使用匹配2,就要将已有的字符串改成另一个字符串,替换
3,想要按照指定的方式将字符串转成多个子串。切割
4,想要拿到符合需求的字符串子串,获取
练习:
import java.util.*; class RegexTest { public static void main(String[] args) { // test_1(); // ipSort(); checkMail(); } //一、需求:将字符串转成:我要进黑马! public static void test_1() { String str = "我我...我我我...我...要要...要要...进进...进进进..进..黑...黑黑...马..!";; str = str.replaceAll("\.+",""); //1,先将"."去掉 System.out.println(str); str = str.replaceAll("(.)\1+","$1");//2,然后将多个重复的内容转成单个内容 System.out.println(str); } /* 二、需求:将ip地址进行地址段顺序的排序 192.168.1.100 110.56.89.13 2.2.2.2 10.10.10.10 要处理的问题:地址段数字直接比较时由于位数不同会导致“110<2”的情况 解决思路:还按照字符串自然顺序,将不足三位的数字补足三位 1,按照每一段需要的0补齐,保证每一段至少有位 2,将每一段只保留三位,将多余的0去除 */ public static void ipSort() { String ip = "192.168.1.100 110.56.89.13 2.2.2.2 10.10.10.10"; //补两个0,每一段至少三位 ip = ip.replaceAll("(\d+)","00$1");//规则:连续的数字(),规则被重用,都在前面加两个0 System.out.println(ip); //将多余的0去除,只留下三位 ip = ip.replaceAll("0*(\d{3})","$1");//规则:0出现0次或多次(后面跟三个数字)$1取结尾 System.out.println(ip); //$N 表示匹配后,被正则中第N个括号所获取的内容 String[] arr = ip.split(" +");//切割 TreeSet<String> ts = new TreeSet<String>(); for (String s : arr ){ //将地址中ip存入TreeSet集合,自动排序 ts.add(s); } for (String s : ts ){ //遍历获取;定义规则,去除前面的0 System.out.println(s.replaceAll("0*(\d+)","$1")); } } /* 三、需求:对邮件地址进行校验 规则:邮箱名:[字母数字下划线]{6~12位} @ [字母数字如qq/163等] . [后缀名,子母com/cn等] */ public static void checkMail() { String mail = "hahaha@163.com.cn"; String reg = "[a-zA-z0-9_]{6,12}@[a-zA-Z0-9]+(\.[a-zA-Z]+)+";//较为精确的匹配 reg = "\w+@\w+(\.\w+)+";//相对不太精确的匹配<span style="font-family: Arial, Helvetica, sans-serif;">(1@1.1)</span> // mail.indexOf("@") !=-1; //简陋的匹配(@) System.out.println(mail.matches(reg)); } }
运行结果:
1,去重复
2,ip管理:
获取练习:网页爬虫(蜘蛛)
获取指定页面中符合规则的信息,如邮箱
定义正则,扫描网页,获取页面中的所有邮箱地址
实现:
import java.io.*; //io包 import java.util.regex.*;//正则包 import java.net.*; //URL class RegexTest2 { public static void main(String[] args) throws Exception { // getMails_1(); getMails_2(); } //二、获取互联网上网页中的邮箱 public static void getMails_2() throws Exception { URL url = new URL("http://tieba.baidu.com/p/2314539885"); URLConnection con = url.openConnection(); BufferedReader bufIn = new BufferedReader(new InputStreamReader(con.getInputStream())); myRegex(bufIn); } //一、获取指定文档中邮件地址 //使用获取功能,用到Pattern 和Matcher类 public static void getMails_1() throws Exception { BufferedReader bufr = new BufferedReader(new FileReader("1.txt"));//读取文档 myRegex(bufr); } public static void myRegex(BufferedReader buf) throws Exception { String regex = "\w+@\w+(\.\w+)+";//邮箱规则 Pattern p = Pattern.compile(regex); //1,将规则封装成对象 String line = null; while ((line=buf.readLine()) !=null) { Matcher m = p.matcher(line); //2,获取匹配器 while (m.find()) //匹配器方法,查找符合规则子串 { System.out.println(m.group());//获取字串 } } } }这个执行获取操作的网页爬虫真正体现了正则表达式的威力,随便试了一个贴吧里资源帝留邮箱的帖子页面,轻易就抓取了几十个邮箱地址
运行结果:
小结:
正则表达式的强大之处在于在定义regex正则时,寥寥几个符号就能取代大量的String 字符串操作,大大的简化了书写,提高开发效率;缺点是规则较多时阅读性较差,站在开发的角度来讲,其好处是远远大于弊端的。
获取操作要重点掌握,Pattern类和Matcher类