概念:
正则表达式:即符合一定规则的表达式
作用:专门用于操作字符串
特点:用一些特定的符号来替代一些代码操作,简化书写
学习正则表达式就是在学习指定其规则的符号的使用,即如何定义规则,详细方法参见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(编号n)
想要使用已有的组可以通过\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类