正则表达式

正则表达式

实例1:匹配QQ号码
实例2:匹配手机号码
实例3:匹配用户名
实例4:对字符串进行切割
实例5:替换指定字符
实例6:获取字符串中3个字母的单词
实例7:去除重复字符
实例8:对IP地址进行排序
实例9:对邮件地址进行效验
实例10:获取网页上的邮件地址

一、正则表达式概述

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,
组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

正则表达式的特点是:
1. 灵活性、逻辑性和功能性非常的强;
2. 可以迅速地用极简单的方式达到字符串的复杂控制。
3. 对于刚接触的人来说,比较晦涩难懂。

由于正则表达式主要应用对象是文本,因此它在各种文本编辑器场合都有应用,
小到著名编辑器EditPlus,大到Microsoft Word、Visual Studio等大型编辑器,
都可以使用正则表达式来处理文本内容。

正则表达式的构造摘要
构造 匹配
 
字符
x 字符 x
\\ 反斜线字符
\0n 带有八进制值 0 的字符 n (0 <= n <= 7)
\0nn 带有八进制值 0 的字符 nn (0 <= n <= 7)
\0mnn 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh 带有十六进制值 0x 的字符 hh

\t 制表符 ('\u0009')
\n 新行(换行)符 ('\u000A')
\r 回车符 ('\u000D')
\f 换页符 ('\u000C')
\a 报警 (bell) 符 ('\u0007')
\e 转义符 ('\u001B')
\cx 对应于 x 的控制符
 
字符类
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
 
预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
 
POSIX 字符类(仅 US-ASCII)
\p{Lower} 小写字母字符:[a-z]
\p{Upper} 大写字母字符:[A-Z]
\p{ASCII} 所有 ASCII:[\x00-\x7F]
\p{Alpha} 字母字符:[\p{Lower}\p{Upper}]
\p{Digit} 十进制数字:[0-9]
\p{Alnum} 字母数字字符:[\p{Alpha}\p{Digit}]
\p{Punct} 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} 可见字符:[\p{Alnum}\p{Punct}]
\p{Print} 可打印字符:[\p{Graph}\x20]
\p{Blank} 空格或制表符:[ \t]
\p{Cntrl} 控制字符:[\x00-\x1F\x7F]
\p{XDigit} 十六进制数字:[0-9a-fA-F]
\p{Space} 空白字符:[ \t\n\x0B\f\r]
 
java.lang.Character 类(简单的 java 字符类型)
\p{javaLowerCase} 等效于 java.lang.Character.isLowerCase()
\p{javaUpperCase} 等效于 java.lang.Character.isUpperCase()
\p{javaWhitespace} 等效于 java.lang.Character.isWhitespace()
\p{javaMirrored} 等效于 java.lang.Character.isMirrored()
 
Unicode 块和类别的类
\p{InGreek} Greek 块(简单块)中的字符
\p{Lu} 大写字母(简单类别)
\p{Sc} 货币符号
\P{InGreek} 所有字符,Greek 块中的除外(否定)
[\p{L}&&[^\p{Lu}]]  所有字母,大写字母除外(减去)
 
边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾
 
Greedy 数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
 
Reluctant 数量词
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
 
Possessive 数量词
X?+ X,一次或一次也没有
X*+ X,零次或多次
X++ X,一次或多次
X{n}+ X,恰好 n 次
X{n,}+ X,至少 n 次
X{n,m}+ X,至少 n 次,但是不超过 m 次
 
Logical 运算符
XY X 后跟 Y
X|Y X 或 Y
(X) X,作为捕获组
 
Back 引用
\n 任何匹配的 nth 捕获组
 
引用
\ Nothing,但是引用以下字符
\Q Nothing,但是引用所有字符,直到 \E
\E Nothing,但是结束从 \Q 开始的引用
 
特殊构造(非捕获)
(?:X) X,作为非捕获组
(?idmsux-idmsux)  Nothing,但是将匹配标志i d m s u x on - off
(?idmsux-idmsux:X)   X,作为带有给定标志 i d m s u x on - off
的非捕获组  (?=X) X,通过零宽度的正 lookahead
(?!X) X,通过零宽度的负 lookahead
(?<=X) X,通过零宽度的正 lookbehind
(? (?>X) X,作为独立的非捕获组


正则表达式:符合一定规则的表达式
作用:用于操作字符串
特点:用于一些特定的符号来表示一些代码操作,这样就简化书写。
好处:可以简化对字符串的复杂操作,
弊端:符号定义越多,正则越多,阅读性越差。


二、正则表达式-匹配

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

如果匹配成功,则可以通过 start、end 和 group 方法获取更多信息。
只要有一处不符合规则,就匹配结束,返回false
当且仅当整个区域序列匹配此匹配器的模式时才返回 true。

实例1:匹配QQ号码

如果QQ限定在5-11位之间
第1位不能是0,必须是1-9
第2位以及以后都是数字

class MatchesQQ{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args) {
		String qq1 = "012345";
		String qq2 = "a12345";
		String qq3 = "-123456";
		String qq4 = "1234";
		String qq5 = "123456789012";
		String qq6 = "123456789";
		String reg = "[1-9]\\d{4,10}";
		sop("qq1:"+qq1.matches(reg));//false
		sop("qq2:"+qq2.matches(reg));//false
		sop("qq3:"+qq3.matches(reg));//false
		sop("qq4:"+qq4.matches(reg));//false
		sop("qq5:"+qq5.matches(reg));//false
		sop("qq6:"+qq6.matches(reg));//true
	}
}
实例2:匹配手机号码

匹配前两位,只要后面9位都是数字就行,
当然目前有的号段并未开通,但暂时不考虑。
手机号码有13XXX、15XXX、18XXX号段

class MatchesTel{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args) {
		String tel1 = "12011110000";
		String tel2 = "186111100002";
		String tel3 = "1351111000";
		String tel4 = "A3511112222";
		String tel5 = "18600001111";
		//手机号码必须是11位数字
		//第1位不能是0,必须是1
		//第2位只能是3、5、8.
		//第3位到第11位都是任何数字
		String reg = "[1][358]\\d{9}";
		sop("tel1:"+tel1.matches(reg));//false
		sop("tel2:"+tel2.matches(reg));//false
		sop("tel3:"+tel3.matches(reg));//false
		sop("tel4:"+tel4.matches(reg));//false
		sop("tel5:"+tel5.matches(reg));//true
	}
}
实例3:匹配用户名

用户名长度在6-15位之间
用户名以字母和数字组成,只能以字母开头,只能包含'-'以及'_'
^ 行的开头 只能是任何字母大小写
$ 行的结尾

class MatchesUser{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args) {
		String user1 = "wgxin";
		String user2 = "jiewin";
		String user3 = "wgx*abc";
		String user4 = "020jiuguijiu";
		String user5 = "A6_1-2345612345";
		String reg = "^[a-zA-Z][a-zA-Z0-9_-]{5,14}$";
		sop("user1:"+user1.matches(reg));//false
		sop("user2:"+user2.matches(reg));//true
		sop("user3:"+user3.matches(reg));//false
		sop("user4:"+user4.matches(reg));//false
		sop("user5:"+user5.matches(reg));//true
	}
}

三、正则表达式-切割

用到的方法:split(String regex)

实例4:对字符串进行切割
class SplitDemo{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args) {
		//splitUser1();
		//splitUser2();
		//splitUser3();
		//splitURL();
		splitDieCi();
	}
	//如果切割符号只出现连续1个
	public static void splitUser1(){
		String user = "zhangsan lisi wangwu";
		String reg = " ";//用一个空格切割
		String[] arr = user.split(reg);
		for(String s:arr){
			sop(s);
		}
	}
	//切割符号连续出现多次并且个数不相等
	public static void splitUser2(){
		String user = "zhangsan  lisi    wangwu";
		String reg = " +";//用多个空格切割
		String[] arr = user.split(reg);
		for(String s:arr){
			sop(s);
		}
	}
	//切割符号不能用“.”切割,因为它是正则表达式里的特殊符号,必须先进行转义
	public static void splitUser3(){
		String user = "zhangsan.lisi.wangwu";
		String reg = "\\.";//不能这样写\.
		String[] arr = user.split(reg);
		for(String s:arr){
			sop(s);
		}
	}
	//使用叠词切割
	public static void splitDieCi(){
//		//用.来表示任意字符,用(.)1来表示一组。
//		//但是1必须先用\转义,同时\也要转义一次,最后就是(.)\\1
//		String user = "zhangshankklisibbwangwu";
//		String reg = "(.)\\1";

		//如果叠词数出现的个数不同,就在后面添加‘+’
		String user = "zhangshankklisibbwangwu";
		String reg = "(.)\\1";
		reg =  "(.)\\1+";
		String[] arr = user.split(reg);
		for(String s:arr){
			sop(s);
		}
	}
}

四、正则表达式-替换

replaceAll
public String replaceAll(String replacement)
替换模式与给定替换字符串相匹配的输入序列的每个子序列。

此方法首先重置匹配器。然后,它将扫描输入序列以查找该模式的匹配项。
不属于任何匹配的字符被直接添加到结果字符串;在结果中每个匹配都将被替换字符串所替换。
替换字符串可能包含到已捕获子序列的引用,如在 appendReplacement 方法中一样。

注意,在替换字符串中使用反斜线 (\) 和美元符号 ($) 可能导致与作为字面值替换字符串时所产生的结果不同。
美元符号可视为到如上所述已捕获子序列的引用,反斜线可用于转义替换字符串中的字面值字符。

在给定正则表达式 a*b、输入 "aabfooaabfooabfoob" 和替换字符串 "-" 的情况下,
为该表达式针对匹配器调用此方法将产生字符串 "-foo-foo-foo-"。

调用此方法将更改此匹配器的状态。如果在将来的匹配操作中使用该匹配器,则应该首先重置它。

实例5:替换指定字符
class ReplaceDemo{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args) {
		replace1();
		replace2();
		replace3();
	}
	//如果字符串中连续出现5个以上的数字,就将其替换成#
	public static void replace1(){
		String str = "wgxin135000001111jiewin1156xin123456guangwu";
		sop(str.replaceAll("\\d{5,}","#"));
	}
	//将叠词替换成&号
	public static void replace2(){
		String str = "wgxin0101335500001111jiew111in";
		sop(str.replaceAll("(.)\\1+","&"));
	}
	//将叠词替换成单个词,$1 表示一组叠词
	public static void replace3(){
		String str = "aaabbbbbcccccddddddefg111122234445565321";
		sop(str.replaceAll("(.)\\1+","$1"));
	}
}
/*
wgxin#jiewin1156xin#guangwu
wgxin0101&&&&jiew&in
abcdefg1234565321
*/

五、正则表达式-获取

获取就是将字符串中符合规则的子串取出。

操作步骤:
1、将正则表达式封装成对象。
2、让正则对象与要操作的字符串关联。
3、关联后,获取正则匹配引擎,也就匹配器。
4、通过引擎对符合规则的子串进行操作,比如取出。

java.util.regex
Pattern
正则表达式的编译表示形式。

指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用
于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配
所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。

因此,典型的调用顺序是:
 Pattern p = Pattern.compile("a*b");
 Matcher m = p.matcher("aaaaab");
 boolean b = m.matches();

方法:
Matcher matcher(CharSequence input)
 创建匹配给定输入与此模式的匹配器。
static boolean matches(String regex, CharSequence input)
 编译给定正则表达式并尝试将给定输入与其匹配。
static Pattern compile(String regex)
 将给定的正则表达式编译到模式中。
static Pattern compile(String regex, int flags)
 将给定的正则表达式编译到具有给定标志的模式中。
 
int end() 返回最后匹配字符之后的偏移量。
int start() 返回以前匹配的初始索引。
String group() 返回由以前匹配操作所匹配的输入子序列。
String pattern() 返回在其中编译过此模式的正则表达式。
Pattern pattern() 返回由此匹配器解释的模式。
boolean matches() 将尝试将整个区域与模式匹配。
boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列。
 
\b 单词边界

实例6:获取字符串中3个字母的单词

需求:编写正则表达式,从字符串中获取3个字母的单词

import java.util.regex.*;
class GetDemo{
	public static void sop(Object obj){System.out.println(obj);}
	public static void main(String[] args){
		//定义字符串
		String str = "ming tian fang jia le,da jia, haha.";
		
		//设置正则表达式。从字符串中获取3个字母的单词
		String reg = "\\b[a-z]{4}\\b";
		
		//把正则表达式封装成对象
		Pattern p = Pattern.compile(reg);
		
		//把对象和字符串关联,获取匹配器对象。
		Matcher m = p.matcher(str);
		
		//其实String类中的matches方法,用的就是Pattern和Matcher对象来完成的。
		//只不过被String的方法封装后,用起来较为简单,但功能却单一。
		//find()尝试查找与该模式匹配的输入序列的下一个子序列。
		while(m.find()){
			String word = m.group();	//获取匹配后的结果
			int s = m.start();			//返回以前匹配的初始索引
			int e = m.end();			//返回最后匹配字符之后的偏移量
			sop(word+" "+s+"-"+e);
		}
	}
}
实例7:去除重复字符

将如下字符串转换成:我要学编程.
“我我..我..要要....学.....学学...编编...编程”

到底用四种功能中的哪一种?或哪几个?

思路:
1、匹配:用于只想知道该字符是对是错。
2、替换:用于将已有的字符串变成另外一个字符串。
3、切割:用于按照自定的方式将字符串变成多个字符串,获取规则以外的子串。
4、获取:用于获取符合要求的字符串子串,

class RegexTest{
	public static void main(String[] args){
		String str = "我我...我...要要...学...学学....编编.....编程";
		
		//先把字符串中的“.”替换掉
		str = str.replaceAll("\\.+","");
		
		//在把字符串中的重叠字符去掉
		str = str.replaceAll("(.)\\1+","$1");
		System.out.println(str);
	}
}
实例8:对IP地址进行排序

将下列IP地址进行地址段顺序的排序。
192.168.0.100 159.52.56.101 5.50.30.2 248.54.68.4 68.67.45.05

思路:
1、按最低位的需要来给每一段都补0满足3每段至少都是3位数。
2、然后每一段都只保留3位数。
3、去除每一段的1之前的0都去掉。

import java.util.*;
class IPSort{
	public static void main(String[] args){
		String ip = "192.168.0.100 159.52.56.101 5.50.30.2 248.54.68.4 68.67.45.05";
		
		//在每一段前面都补2个0
		ip = ip.replaceAll("(\\d+)","00$1");
		
		//保留每一段的后3位数
		ip = ip.replaceAll("0*(\\d{3})","$1");
		
		//用空格切割成多段存入字符串数组中
		String[] arr = ip.split(" ");
		
		//使用集合方式把数组中的元素进行自然排序
		TreeSet ts = new TreeSet();
		for(String s:arr){
			ts.add(s);
		}

		//遍历集合,将每一段数前面的0都去掉
		//方法是先用\\d+获取每一段数字进行封组,
		//利用0*把第一位是0的都去掉
		for(String s:ts){
			System.out.println(s.replaceAll("0*(\\d+)","$1"));
		}
	}
}
/*
运行结果:
5.50.30.2
68.67.45.5
159.52.56.101
192.168.0.100
248.54.68.4
*/
实例9:对邮件地址进行效验

matches()方法返回字符串与正则表达式匹配后的结果,true或false

import java.util.regex.*;
class CheckEmail{
	public static void main(String[] args){
		String mail = "[email protected]";
		
		//最简单最懒的校验方法,安全性极差,如[email protected],都能匹配
		//String reg = "\\w+@\\w+(\\.\\w+)+";
		
		//稍微安全的校验方法
		String reg = "^[a-zA-Z][a-zA-Z0-9_-]{5,14}+@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}";
		System.out.println(mail.matches(reg));
	}
}
/*
注释:
^[a-zA-Z]			 第一位只能是a-z或A-Z,
[a-zA-Z0-9_-]{5,14}  第二位后面的可以是a-zA-Z0-9还有_-。
{5,14}+				 @前面名称长度从6到15位包括15位。
@[a-zA-Z0-9]+		 @的后面可以是a-z或A-Z或0-9
(\\.[a-zA-Z]+)		 “.”必须用\\转义,用括号把表达式进行分组复用
{1,2}				 可以复用1-2次,一般邮箱域名最多也就是二级,比如@sina.com.cn
*/

六、网页爬虫

网页爬虫简单说就是互联网程序的一种代名词,也可以指一段小程序,也可以指使用者。
特点,利用这个小程序可以获取指定的网页上的数据,例如获取邮箱,给邮箱发送广告。

URLConnection 类中的方法
InputStream getInputStream() 返回从此打开的连接读取的输入流。

实例10:获取网页上的邮件地址
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.*;
class GetEmail{
	public static void main(String[] args) throws Exception{
		//getEmail();
		getWebEmail();
	}
	//获取本地文件中的email地址
	public static void getEmail() throws Exception{
		//创建字符读取流缓冲区
		BufferedReader bufr = new BufferedReader(new FileReader("email.txt"));
		String line = null;
		//String mailreg = "\\w+@\\w+(\\.\\w+)+";
		String mailreg = "\\b[a-zA-Z][a-zA-Z0-9_-]{3,14}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}";
		//将表达式封装成模式
		Pattern p = Pattern.compile(mailreg);
		//读取字符流缓冲区中的一行数据
		while((line=bufr.readLine())!=null){
			//把数据与正则表达式模式匹配
			Matcher m = p.matcher(line);
			//匹配下一个
			while(m.find()){
				//返回正确匹配后的结果打印出去
				System.out.println(m.group());
			}
		}
	}
	//获取网络URL中的邮件地址
	public static void getWebEmail() throws Exception{
		URL url1 = new URL("http://edu.csdn.net/main/about/contact.shtml");
		URL url2 = new URL("http://www.douban.com/event/14146775/discussion/40108760/");
		//返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 
		URLConnection conn = url2.openConnection();
		//从conn打开的连接读取输入流,存入字符读取流缓冲区。
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		String reg = "\\b[a-zA-Z][a-zA-Z0-9_-]{3,14}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}";
		Pattern p = Pattern.compile(reg);
		//使用TreeSet集合的自然排序功能。
		TreeSet ts = new TreeSet();
		String line = null;
		while((line=bufIn.readLine())!=null){
			Matcher m = p.matcher(line);
			while(m.find()){
				ts.add(m.group());//添加到集合中
				//System.out.println(m.group());
			}
		}
		//遍历集合中的数据
		for(String s:ts)
			System.out.println(s);
	}
}

你可能感兴趣的:(java)