• 正则表达式__【匹配、切割、替换】【获取:Pattern & Matcher】【网页爬虫(蜘蛛)】



    概念:

    正则表达式:即符合一定规则的表达式
    作用:专门用于操作字符串
    特点:用一些特定的符号来替代一些代码操作,简化书写
    学习正则表达式就是在学习指定其规则的符号的使用,即如何定义规则,详细方法参见API文档Pattern中正则表达式的规则组成
    优点:简化字符串操作步骤
    弊端:符号定义多时,正则越长,阅读性越差

    具体操作功能:

    1,匹配:String matches()方法;设定regex规则,只要有一处不匹配,就返回false
    2,切割: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类



  • 相关阅读:
    (笔记)电路设计(十三)之振荡电路的应用
    (笔记)电路设计(十二)之高速数字系统滤波电容的设计应用
    爬楼梯问题 leetcode70
    偏函数
    柯里化
    插入排序
    选择排序
    冒泡排序
    解包(封装和解构)、丢弃变量
    数据类型之集合
  • 原文地址:https://www.cnblogs.com/Joure/p/4337201.html
Copyright © 2020-2023  润新知