黑马程序员---正则表达式

  ------- android培训、java培训、期待与您交流! ----------

 

正则表达式简述

符合一定规则的表达式。

作用:用于专门操作字符串。

特点:用一些特定的符号来表示一些代码操作,这样就简化了书写。

好处:可以简化对字符串的复杂操作。

弊端:符号定义越多,正则越长,阅读性越差。

具体操作功能简述

1.匹配:String类中的 matches方法,用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。

2.切割:String类中的 split方法。

3.替换:String类中的 replaceAll方法。

4.获取:将字符串中符合规则的子串取出。

   操作步骤:1.将正则表达式封装成对象。

                     2.让正则对象和要操作的字符串相关联。

                     3.关联后,获取正则匹配引擎。

                     4.通过引擎,对符合规则的子串进行操作。比如:取出。

演示:

1.匹配

String类中有一个方法:

 boolean matches(String regex)(regex:正则表达式)
          告知此字符串是否匹配给定的正则表达式。

点击“正则表达式”会跳转到 java.util.regex 类 Pattern

正则表达式的编译表示形式:

字符类
[abc] abc(简单类)
[^abc] 任何字符,除了 abc(否定)
[a-zA-Z] azAZ,两头的字母包括在内(范围)
[a-d[m-p]] admp[a-dm-p](并集)
[a-z&&[def]] def(交集)
[a-z&&[^bc]] az,除了 bc[ad-z](减去)
[a-z&&[^m-p]] az,而非 mp[a-lq-z](减去)

一个方括号代表一个字符,里面是可以可以匹配的值。如果从哪到哪一个范围内都可以匹配,就写[a-z]

预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]

 

Greedy 数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n
X{n,} X,至少 n
X{n,m} X,至少 n 次,但是不超过 m

 使用正则表达式,校验QQ号码:

class RegexTest 
{
	public static void main(String[] args) 
	{
		//checkQQ_1("1245gsdf644");
		checkQQ_2("123555");
	}

	//使用正则表达式,校验QQ号码
	public static void checkQQ_2(String QQ)
	{
		//boolean matches(String regex);
		String regex = "[1-9][0-9]{4,14}";
		boolean flag = QQ.matches(regex);
		if(flag)
		{
			System.out.println(QQ+"...is OK");
		}
		else
		{
			System.out.println("非法QQ:"+QQ);
		}
	}

	//对QQ号码进行校验
	//长度:5~15、0不能开头、只能是数字
	//这种校验方法,使用String类和Integer类中的方法进行组合,但是代码过于复杂。
	public static void checkQQ_1(String QQ)
	{
		int len = QQ.length();
		if(len>=5 && len<=15)
		{
			if(!QQ.startsWith("0"))//Integer.parseInt("12a");NumberFormatException
			{
				try
				{
					long qq = Long.parseLong(QQ);
					System.out.println("QQ号:"+qq);
				}
				catch (NumberFormatException e)
				{
					System.out.println("出现非法字符");
				}
				
//				char[] arr = QQ.toCharArray();
//				boolean flag = true;
//				for(int x=0; x='0' && arr[x]<='9'))
//					{
//						flag = false;
//						break;
//					}
//				}
//				if(flag)
//				{
//					System.out.println("您输入的QQ号码是:"+QQ);
//				}
//				else
//				{
//					System.out.println("非法字符");
//				}
			}
			else
			{
				System.out.println("不能以0开头");
			}
		}
		else
		{
			System.out.println("长度错误");
		}
	}
}

 

作业

匹配手机号

手机号段只有:13***,15***,18***

class RegexTest 
{
	public static void main(String[] args) 
	{
		checkPhoneNumber("13121456789");
	}

	/*
	匹配手机号
    手机号段只有:13***,15***,18***
    */
	public static void checkPhoneNumber(String tel)
	{
		String regex = "[1][358]\\d{9}";
		System.out.println( tel.matches(regex) );
	}

}

 2.切割

 String[] split(String regex)
          根据给定正则表达式的匹配拆分此字符串。

为了让规则的结果被重[chóng]用,可以将规则封装成一个组,用()完成。组的出现都要编号,从1开始。想要使用已有的组,可以通过 \n 的形式获取。(n是组的编号)

((())()) 代表几个组呢?有几个左括号就有几组。那么哪个是第一组呢?第一个左括号就是第一个组。

组和捕获

捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:

1     ((A)(B(C)))
2     \A
3     (B(C))
4     (C)

组零始终代表整个表达式。

class RegexSplit 
{
	public static void main(String[] args) 
	{
		//splitStr( "hello,,,world,,,!" , ",+" );//按照多个逗号来切。
		//splitStr( "hello.world.!" , "\\." );//按照点来切,点是正则表达式里的特殊符号,所以需要转义。
		//splitStr( "C:\\abc\\a.txt" , "\\\\" );//字符串里的斜线要出来就是一对。
		//splitStr( "goodaamorningkk!" , "(.)\\1" );//按照叠词切。把要重用的部分用小括号括起来封装成为一个组。
		                                     //这个组封装起来以后会有一个自动的编号,从1开始。
						//第二个位置和第一组那个结果是一致的,怎么使用这个组呢?\1
		splitStr( "goodaaamorningzzzz!" , "(.)\\1+" );//用多个重复的任意字符完成切割。
	}

	public static void splitStr(String str, String regex)
	{
		String[] arr = str.split(regex);
		for(String subStr : arr)
		{
			System.out.println(subStr);
		}
	}
}

3.替换

 String replaceAll(String regex,String replacement)
          使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

用$获取组的概念(在正则表达式外面获取):$1代表:获取前一个规则里面的第一个组。

class RegexSplit 
{
	public static void main(String[] args) 
	{
		String str = "fhj5365474iah5435453ghia534543ghi";//将字符串中的数字替换成#。
		replaceAllDemo( str , "\\d{5,}" , "#" );

		String str1 = "goodaaamorningzzzz!";//将将重叠的字符替换成一个字符。zzzz->z
		replaceAllDemo( str1 , "(.)\\1+" , "$1" );//$1代表:拿前一个规则里面的第一个组。
	}

	public static void replaceAllDemo(String str, String regex, String replacement)
	{
		str = str.replaceAll(regex, replacement);
		System.out.println(str);
	}
}

 4.获取

正则到底属于谁呢?属于:

java.util.regex
Pattern

public final class Pattern

extends Object

implements Serializable

正则表达式的编译表示形式。

没有构造函数,有一静态方法可以得到本类对象。

static Pattern compile(String regex)
          将给定的正则表达式编译到模式中。

正则与要作用的字符串相关联,用此方法:

 Matcher matcher(CharSequence input)
          创建匹配给定输入与此模式的匹配器。

java.lang  接口 CharSequencechar 值的一个可读序列。有个直接已知子类是String。

Matcher 类型的返回值是此模式的新匹配器或者称引擎。

 

java.util.regex 

Matcher 

通过解释 Patterncharacter sequence 执行匹配操作的引擎。

boolean matches()
          尝试将整个区域与模式匹配。

获取怎么获取呢?先查找:

 boolean find()
          尝试查找与该模式匹配的输入序列的下一个子序列。

找到了再用group方法获取:

String group()
          返回由以前匹配操作所匹配的输入子序列。

 

 int start()
          返回以前匹配的初始索引。

 

 int end()
          返回最后匹配字符之后的偏移量。

 "ming tian jiu yao fang jia le, da jia.";//要把这里面连续三个字符相连的子串取出来。

import java.util.regex.*;

class RegexDemo 
{
	public static void main(String[] args) 
	{
		getDemo();
	}

	public static void getDemo()
	{
		String str = "ming tian jiu yao fang jia le, da jia.";//要把这里面连续三个字符相连的子串取出来
		//str = "01234567";
		//String regex = "[1-9]\\d{4,14}";
		String regex = "\\b[a-z]{4}\\b";

		//将规则封装成对象
		Pattern p = Pattern.compile(regex);

		//让正则与要作用的字符串相关联,得到引擎。
		Matcher m = p.matcher(str);

		//使用引擎对字符串进行操作。
		//System.out.println(m.matches());
		//其实String类中的matches方法,用的就是Pattern和Matcher对象来完成的。
		//只不过被String类的方法封装后,用起来简单,功能却单一。
		//想要用到更多的方法还是要找到Matcher这个对象,我们发现它里面也有replaceAll方法,
		//除了这些方法外,它还有更牛的方法,String没有封装过的。比如:获取。
		//matches作用于整个字符串,索引位置改变到正则表达式匹配后的位置。

		while(m.find())//先查找
		{
			System.out.println(m.group());//再获取
			System.out.println(m.start()+"......"+m.end());
		}		
	}
}

正则表达式练习一

将下列字符串转成:我要学编程。

"我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程"

自己的思路

class RegexTest1 
{
	public static void main(String[] args) 
	{
		test();
	}

	public static void test()
	{
		String str = "我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程";

		String reg1 = "[\\.]+";//定义正则表达式:一个或多个点。

		String[] arr = str.split(reg1);//用一个或多个点切割字符串,变成字符串数组。

		StringBuilder sb = new StringBuilder();//将字符串数组里的每一个字符串元素添加到StringBuilder里。
		for(String string : arr)
		{
			sb.append(string);
		}

		str = new String(sb); //将StringBuilder变成新的字符串。

		System.out.println(str);
		//"我我我我我要要要要要要学学学学学学编编编编编程程程程程"

		String reg2 = "(.)\\1+";//定义正则表达式:重复的任意字符(两个或两个以上)

		str = str.replaceAll(reg2,"$1");//用前一个正则表达式里面的第几个组来替换符合前一个正则的字符

		System.out.println(str);
		//我要学编程
	}
}

老师的思路

更简捷,两步完成。

class RegexTest1 
{
	public static void main(String[] args) 
	{
		test();
	}

	/*
	需求:
	将下列字符串转成:我要学编程.
	
	到底用四种功能中的哪一个呢?或者哪几个呢?
	思路方式:
	1,如果只想知道该字符是否对还是错,使用匹配。
	2,想要将已有的字符串变成另一个字符串,替换。
	3,想要按照自定的方式将字符串变成多个字符串。切割。获取规则以外的子串。
	4,想要拿到符合需求的字符串子串,获取。获取符合规则的子串。
	*/

	public static void test()
	{
		String str = "我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程";

		/*
		将已有字符串变成另一个字符串。使用 替换功能。
		1,可以先将 . 用 "" 替换。
		2,在将多个重复的内容变成单个内容。
		*/

		str = str.replaceAll("\\.+","");
		System.out.println(str);
		//我我我我我要要要要要要学学学学学学编编编编编程程程程程

		str = str.replaceAll("(.)\\1+","$1");
		System.out.println(str);
		//我要学编程		
	}
}

正则表达式练习二

192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30
 将ip地址进行地址段顺序的排序。

自己的思路

import java.util.TreeSet;
import java.util.Comparator;
class RegexTest2
{
	public static void main(String[] args) 
	{
		test();
	}

	/*
	192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30
	将ip地址进行地址段顺序的排序。
	*/

	public static void test()
	{
		String str = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";

		String[] arr = str.split(" ");//将ip字符串按照空格切开,变成一个一个的ip字符串。
		/*
		192.68.1.254
		102.49.23.013
		10.10.10.10
		2.2.2.2
		8.109.90.30
		*/
		TreeSet ts = new TreeSet(new IntComparator());//TreeSet集合是会自动排序的集合,传入自定义的比较器。
		for(String ip : arr)//遍历ip字符串数组
		{
			String[] ipHead = ip.split("\\.");//ip地址字符串按照 "." 切开。
			ts.add(ipHead[0]);//将ip地址的头段存入TreeSet集合,以便于排序。
		}
		//排序后的ip头
		System.out.println(ts);//[2, 8, 10, 102, 192]	

		StringBuilder sb = new StringBuilder();
		for(String ipHead : ts)//遍历TreeSet集合,以便将ip头与原ip字符串做匹配。
		{
			for(String ip : arr)//遍历ip字符串数组。
			{
				if(ip.startsWith(ipHead+"."))//如果这个ip字符串是以ip头加点开头的话,
				{
					sb.append(ip+" ");//就将这个ip字符串存入字符串缓冲区。
				}
			}
		}
		str = new String(sb);//得到新串,排好序的。
		System.out.println(str);
		//2.2.2.2 8.109.90.30 10.10.10.10 102.49.23.013 192.68.1.254
	}
}

//"108","18"...要以字符串中整数的数值大小进行排序的话,
//首先以字符串的长短排序,
//如果字符串的长度相等,再以自然顺序排序。
class IntComparator implements Comparator
{
	public int compare(String str1, String str2)
	{
		int num = new Integer( str1.length() ).compareTo( new Integer(str2.length()) );
		if(num==0)
		{
			return str1.compareTo(str2);
		}
		else
			return num;
	}
}

老师的思路

还按照字符串自然顺序,只要让它们每一段都是3位即可。
 1,按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位。
 2,将每一段只保留3位。这样,所有的ip地址都是每一段3位。

import java.util.TreeSet;

class RegexTest3 
{
	public static void main(String[] args) 
	{
		ipSort();
	}

	public static void ipSort()
	{
		String ip = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";

		ip = ip.replaceAll("(\\d+)","00$1");//将ip的每一段前面都加两个0

		ip = ip.replaceAll("0*(\\d{3})","$1");//将ip的每一段只保留3位

		String[] arr = ip.split(" +");//将ip地址按一个或多个空格切开

		TreeSet ts = new TreeSet();//将所有ip地址存放到TreeSet集合中,按照字符串自然顺序自动排序。

		for(String str : arr)
		{
			ts.add(str);
		}

		StringBuffer sb = new StringBuffer();
		for(String s : ts)
		{
			s=s.replaceAll("0*(\\d+)","$1");//将每一段ip前面的零去掉。
			sb.append(s+" ");
		}

		ip = new String(sb);//得到按地址段排序的ip地址串。

		System.out.println(ip);
	}
}

 

我自己的方法没有考虑到IP地址的每一段,只按照IP地址的头排序了,有些欠缺。

老师的方法考虑到了IP地址的每一段,如果第一段相同,那么按第二段的大小排,以此类推。

数组的排序方法:

1.Arrays.sort();

2.将数组中的元素存放到TreeSet集合中。如果数组中有重复元素,用方法1.

3.先将数组转成List集合,然后再用Collections.sort();

邮箱地址校验:

class RegexTest4 
{
	public static void main(String[] args) 
	{
		checkMail();

	}

	public static void checkMail()
	{
		String mail = "[email protected]";

		String mail2 = "[email protected]";

		String mail3 = "[email protected]";
		
		/*
		邮箱地址的组成:
		1.邮箱前缀名可以由小写字母大写字母数字下划线组成,长度6-12位。
		2.@
		3.域名可以是小写字母大写字母或数字,长度1位到多位。
		
		将 4、5 两个部分封装成组:
		4. \\.
		5.com或者cn等等,由小写字母或大写字母组成,长度一位到多位。

		6.重用以上组,一次或三次。
		*/

		String regex = "[a-zA-Z0-9_]{6,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}";//较为精确的匹配

		System.out.println(mail.matches(regex));
		System.out.println(mail2.matches(regex));
		System.out.println(mail3.matches(regex));

		// \w 单词字符:[a-zA-Z_0-9] 
		
		String reg = "\\w+@\\w+(\\.\\w+)+";//相对不太精确的匹配

		System.out.println(mail.matches(reg));
		System.out.println(mail2.matches(reg));
		System.out.println(mail3.matches(reg));

		//mail.indexOf("@")!=-1;//只要你的邮箱地址里面有@就行。
	}
}


网页爬虫(蜘蛛):

想发垃圾邮件(传播广告),需要获取邮箱地址,使用以下方法:

获取指定文档中的邮件地址。 

使用获取功能。Pattern  Matcher 

import java.io.*;
import java.util.regex.*;

class RegexTest5 
{
	public static void main(String[] args) throws Exception
	{
		getMails();
	}

	/*
	获取指定文档中的邮件地址。
	使用获取功能。Pattern  Matcher
	*/

	public static void getMails() throws Exception
	{
		BufferedReader br = new BufferedReader(new FileReader("mail.txt"));

		String line = null;

		String regex = "\\w+@\\w+(\\.\\w+)+";

		Pattern p = Pattern.compile(regex);

		while((line=br.readLine())!=null)
		{
			Matcher m = p.matcher(line);
			while(m.find())
			{
				System.out.println(m.group());
			}
		}
	}
}

把这些地址存到数据库里面去,或者存到一个文件里面去。

以后学 javaWeb 的时候会学到一个 javaMail,用 java 来写一个邮件发送接收程序。

完全可以通过自己写的程序来给 sina 啊、sohu 啊之类的发送邮件。

自己写个邮件服务器,再把这些地址读出来以后,噼里啪啦发这些垃圾邮件就欧了~

 

刚才我们说了从文档中获取邮箱地址,

现在我们想爬网页,从网页中获取邮箱地址:

我们专门做了一个HTML网页,放到Tomcat服务器的 webapps/myweb/ 文件夹下,双击 bin/startup.bat 开启Tomcat服务器,在浏览器地址栏输入http://192.168.1.101:8080/myweb/mail.html 网址,就可看到网页中的内容。下面我们来获取这个网页中的邮箱地址。【URL、URLConnection】【Pattern、Matcher】

import java.net.*;
import java.io.*;
import java.util.regex.*;

class RegexTest6 
{
	public static void main(String[] args) throws Exception
	{
		getMails();
	}

	public static void getMails() throws Exception
	{
		URL url = new URL("http://192.168.1.101:8080/myweb/mail.html");

		URLConnection conn = url.openConnection();

		BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ) );

		String line = null;

		String regex = "\\w+@\\w+(\\.\\w+)+";

		Pattern p = Pattern.compile(regex);

		while((line=br.readLine())!=null)
		{
			Matcher m = p.matcher(line);
			while(m.find())
			{
				System.out.println(m.group());
			}
		}
	}
}


把 Tomcat 服务器关了以后,就获取不到了。

 

  ------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------

你可能感兴趣的:(黑马日志)