正则表达式__【匹配、切割、替换】【获取: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(编号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类

相关文章

jquery.validate使用攻略(表单校验) 目录 jquery.validate...
/\s+/g和/\s/g的区别 正则表达式/\s+/g...
自整理几个jquery.Validate验证正则: 1. 只能输入数字和字母...
this.optional(element)的用法 this.optional(element)是jqu...
jQuery.validate 表单动态验证 实际上jQuery.validate提供了...
自定义验证之这能输入数字(包括小数 负数 ) &lt;script ...