JAVA正则表达式入门与常用方法总结

     在编写程序的过程中,大家或许经常都会遇到需要将查找字符串,替换字符串、查找特定的字符串,检索字符串。如果完全使用字符串中自带的方法和一些算法来进行处理,不仅会花费大量的时间和精力,同时效率也不一定会很高。

    那么这个时候,正则表达式就有用了。这是专门用来匹配字符串的操作。在java中也有了相关的类。本篇文章主要讲的就是一个简单的正则表达式入门,以及如何使用java中的相关的类来运用正则表达式处理字符串。

Pattern类和Matcher类

     若要在java中使用正则表示,那么必须要了解这2个类。这2个类都是在java.util.regex的包中。
Pattern类

     此主要是用来构造一个匹配模式的。指定为字符串的正则表达式必须编译为此类的实例。然后,可以得到的模式用于创建Matcher对象(接下来会讲到)。依照此正则表达式。该对象可以与任意字符序列匹配。

Matcher类

     此类是通过Pattern对字符序列执行操作的引擎。

     通俗的解释就是,在一大串字符串中,你可能要查找某个特定格式的字符串序列,比如你要在大段文字中查找出电话号码(可以初步理解为只有11个数字,当然现实是不可能的,这里只是将问题简单化)。所以你就要指定一个匹配模式,说明你要找的是连续的11个数字,这个就主要是通过Pattern来构造一个这样的匹配模式。当用pattern构造完毕之后,就需要利用Mathcer类在字符序列中寻找这样满足要求的字符串(即,连续的11为数字) 

    因此,典型的调用顺序为:

Patternp = Patern.compile(“需要查找的字符串”); 

Mactherm = p.matcher(“字符串集合”);

Booleanb = m.matcher();

     第一句的作用是,先将需要查找的字符串进行编译。如此在以后的查找使用过程中,数独会变快,同时还有利于以后的多次使用。第二句就字符串集合传入到搜索引擎中,融搜索引擎来查找是否满足要求的字符串。第三句来说明是否满足要求。

字符类

[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(取2者的交集)

[a-z&&[^bc]]             表示a到z,除了b和c [ad-z](减去)

[a-z&&[^m-p]]            表示a到z,不是m到p,即[a-lp-z](减去)

注意被[]包含了,都只是匹配一个字符。例如[abc]表示匹配的是a、b、c中的任意一个,而不是匹配abc

具体的实例如下:

	//匹配a或b或c
	Pattern p1 = Pattern.compile("[abc]");
	//匹配非a、b、c
	Pattern p2 = Pattern.compile("[^abc]");
	//匹配a到z,不包含m到p
	Pattern p3 = Pattern.compile("[a-z&&[^m-p]]");
	Matcher m = p1.matcher(s);
	System.out.println(m.matches());
	m = p2.matcher(s);
	System.out.println(m.matches());
	m = p3.matcher(s);
	System.out.println(m.matches());

预先定义的字符集

.             表示任何形式的字符

\d           表示数字0到9

\D          表示非数字

\s           表示空白字符(包括换行符,制表符,enter键等)

\S           表示非空白符

\w          表示单词字符(包括26个英文字母的大小写)

\W         表示非单词字符([^\w])

具体实例如下:

(为了方便举例说明问题,以下的代码均采用简化版的写法,但是在编写程序的过程中,大家还是尽量使用标准的写法)

<span style="white-space:pre">	</span>System.out.println("a".matches("[abc]"));
	System.out.println("a".matches("[^abc]"));
	System.out.println("A".matches("[a-zA-Z]"));
	System.out.println("A".matches("[a-z]|[A-Z]"));
	System.out.println("A".matches("[a-z[A-Z]]"));
	System.out.println("R".matches("[A-Z&&[RFC]]"));

数量词

?          一次或者0次

*           0次或多次

+           一次或多次

{n}         恰好n次

{n,}        至少n次

{n,m}       至少n次,至多m次

具体的实例如下:

<span style="white-space:pre">	</span>System.out.println("123445".matches("\\d{4,6}"));   <span style="white-space:pre">		</span>//true
	System.out.println("1".matches("\\d?"));			//true
	System.out.println("12".matches("\\d*"));			//true
	System.out.println("\n\t\r".matches("\\s{4}"));		<span style="white-space:pre">	</span>//false
	System.out.println(" ".matches("\\s"));				//true
	System.out.println("a_8".matches("\\w+"));			//true
	//匹配一个"/"需要四个"/"才能够匹配
	System.out.println("\\".matches("\\\\")); 			//true  

边界词

^            行的开头(不要与[^]弄混淆了,在[]中的^表示非)

$            行的结尾

\b           单词边界

\B          非单词边界

具体的实例如下:

<span style="white-space:pre">	</span>System.out.println("hello sir".matches("^h.*"));				//true
	System.out.println("hello sir".matches(".*r$"));				//true
	System.out.println("hello sir".matches("^h[a-z]{1,3}o\\b.*"));<span style="white-space:pre">			</span>//true
	//匹配空白行
	System.out.println("\n".matches("^[\\s&&^\n]*\\n$"));     <span style="white-space:pre">			</span>//true

查找子字符串

     之前我们讲到的查找字符串都是对整个字符串进行查找,然后判断此字符串是否是满足要求的字符串。但是如果要在一大串的字符中查找满足要求的字符串,那么应该如何查找呢?

     这时需要用到Matcher中的find()函数。find()函数的作用是,查找满足匹配要求的子字符串,返回查找的结果。然后接着此子字符串接着往下寻找,看是否存在满足要求的子字符串。lookingAt()对前面的字符串进行匹配,只有匹配到的字符串在最前面才返回true 。

实例如下:

<span style="white-space:pre">	</span>Pattern p =Pattern.compile("\\d{3,5}");
	String s = "123-34345-234-00";
	Matcher m =p.matcher(s);
	System.out.println(m.matches());  //匹配整个字符串                //true
	m.reset();   
	//注意matches()方法和find()方法会相互影响
	//官方的说法为:重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。 
	//判断能否找到一个能够符合匹配规则字符串的字串,然后从这个字串接着往下找能够匹配到字串
	 //如果要输出字串的开始位置和结束位置,就必须先找到此字串,如果没有找到,则会报错
	System.out.println(m.find());      			
	System.out.println(m.start()+"-"+m.end()); 
	System.out.println(m.find());
	System.out.println(m.start()+"-"+m.end());
	System.out.println(m.find());
	System.out.println(m.start()+"-"+m.end());
	System.out.println(m.find());
		
	//尝试将从区域开头开始的输入序列与该模式匹配。 
	System.out.println(m.lookingAt());                 <span style="white-space:pre">			</span>//true
	System.out.println(m.lookingAt());				 	//true
	System.out.println(m.lookingAt());					//true
	System.out.println(m.lookingAt());					//true
说明:

    当使用了m.match(s)的时候,必须要使用m.reset()方法来重置一下搜索引擎的搜索其实位置。因为当执行完了match()函数之后,正则搜索引擎并不会默认的恢复到原来的字符串的起始位置。所以当执行接下来的函数时,会接着之前的match()函数执行之后往下执行,就会出现匹配失误的情况。所以要执行reset()函数。m.find)是返回找到字符串的那个字符串的开始位置,m.end()是返回找打字符串之后的结束位置的下一个位置。lookingAt()表示的意思是从字符串的其实位置开行查找,所以4个lookingAt()都是从其实位置开始查找,复回的就都是true。

字符串替换

    字符串替换并不是正则表达式中提供的功能。而是在Matcher类提供的功能。主要是使用appendReplacement()方法来进行替换。具体的代码如下:

	Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);   //忽略大小写
	Matcher m = p.matcher("12354 java Java  456 JAVA ILoveJAVA you hateJava dbanbk");
	StringBuffer sb = new StringBuffer();
	int count = 0;
	while(m.find()) {
		count++;
		if(count%2==0) {
			//将匹配到的第偶数的字符串换成java
			m.appendReplacement(sb, "java");   
		} else {
			//将匹配到的第奇数的字符串换成JAVA
			m.appendReplacement(sb, "JAVA");
		}
	}
	System.out.println(sb);
	/*
	output is:12354 JAVA java  456 JAVA ILovejava you hateJAVA
	 */

分组

     前面已经讲到可以使用“+”或者“/”来重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组)。分组号的确定从左边往右数小括号,小括号的位次就是第几个分组。

具体的代码如下:

<span style="white-space:pre">	</span>//分组,整个正则表达式也是一组。每一个组都有一整个组号。
	//组号的确定:左小括号在整个左小括号的位置就是改组的组号。如果某个左小括号是第一个出现,那么就是第一组
	//第二个出现,就是第二组。依次类推
	Pattern p = Pattern.compile("(\\d{3,5})([a-z]{2})");
	String s = "123aa-34345bb-234cc-00";
	 Matcher m = p.matcher(s);
	 while(m.find()) {
		//打印出第一组正则表达式所匹配的字串
		System.out.println(m.group(1));
	}
	

如果要寻找具体的某个组的具体的内容,就需要使用group()方法,向其中传入组号即可。

贪婪模式和非贪婪模式

     之前所讲的数量词其实使用的都是贪婪模式,而在正则表达式中还存在另一种模式,那就是非贪婪模式。

     贪婪模式是指,当进行匹配的时候,首先会全部进行匹配,如果全部无法匹配的时候,然后再减少一个字符,然后接着去匹配。例如当匹配/d{2,5}首先会去匹配5个数字,如果不存在匹配的项,然后再匹配4个数字。依次往下。

     非贪婪模式与贪婪模式恰恰相反。对于/d{2,5}首先回去匹配2个数字,如果不存在匹配项,再去匹配3个数字,依次往下。

     关于贪婪模式和非贪婪模式,具体可以参见这个网址( http://blog.csdn.net/lxcnn/article/details/4756030)。其中有非常详细的讲解。

具体的示例如下:

  贪婪模式

	Pattern p = Pattern.compile(".{3,10}\\d");
	String s = "aaaa5bbbb68";
	Matcher m = p.matcher(s);
	while (m.find()) {
		System.out.println(m.group());
	}

输出结果为:aaaa5bbbb68

默认就是贪婪模式,就是首先以10个任意的字符去匹配,匹配之后就往下寻找,看下一个字符是否为一个数字。然后将结果返回。

  非贪婪模式

<span style="white-space:pre">	</span>Pattern p = Pattern.compile(".{3,10}?\\d");
	String s = "aaaa5bbbb68";
	Matcher m = p.matcher(s);
	while (m.find()) {
		System.out.println(m.group());
	}
输出结果:
aaaa5
bbbb6

可以发现贪婪模式和非贪婪模式仅仅是在.{3,10}后面的一个“?”的区别,但是结果却完全不同。因为非贪婪模式,是首先以3个任意字符去匹配,如果没有匹配成功再去以4个任意字符去匹配。在本例中,首先是以三个任意字符去匹配,匹配成功后,级匹配到aaa时,然后再检查后面的是否是一个数字,如果不是就以4个字符匹配,如果仍然不是接着以5个字符匹配,以此类推。在本例中当匹配到4个a时,发现接下来的是一个数字,符合要求,则打印出aaaa5.然后接着以这种方式往下寻找,找到了bbbb6。所以最后的结果就是aaaa5、bbbb6

其他用法

   这里主要会介绍一些在正则表达式中不常用的方法。主要介绍的是特殊构造和向前引用
特殊构造
例如:

(?=a).{3}表示的在任意的三个字符中第一个字符必须是a.(这里的字符a没有什么其他的含义,仅仅表示字符a)

.{3}(?=a)       表示的是在任意的三个字符的后面必须是一个字符a,但是字符a并不在三个字符中

对于.{3}(?!a),表示的是任意的三个字符的后面一个字符不能为a

对于(?!a).{3}表示在任意的三个字符中的第一个字符,前面不能为a

具体实例如下:

<span style="white-space:pre">	</span>//非匹配(?=a)
	// (?=a).{3}  表示前面为a结果为 a66,算在group中
	// .{3}(?=a)  结果为444,表示后面为a,不算在group中
	//	(?!a).{3} 表示前面部委a
	//  .{3}(?!a)  表示后面不为a
	// .{3}(?<!a)  表示从后往前数 
	Pattern p = Pattern.compile("(?=a).{3}");
	String s = "444a66b";
	Matcher m = p.matcher(s);
	while(m.find()) {
		System.out.println(m.group());
	}


向前引用

例如:

    (\\d\\d)\\1 其中\\1向前引用的标识,表示的是第一组在本例中值得就是(\\d\\d),然后\\1表示的就是跟着(\\d\\d)后面的字符串必须和第一组相同。也就是字符串要满足这样的格式 1212

    (\\d(\\d))\\2 在本例中有2个组(忽略掉正则表达式中的那个大组),2表示的是第2个组,在本例中第一组是(\\d\\d) ,第二组是\\d。那么\\2表示的就是跟在(\\d\\d)后面的必须和第二个\\d相同。如122就满足要求。因为在122中,第一组是12,第二组是2(第一个2),要求接下来的数字和第二组相同,那么接下来的数字也必须是2。所以112符合要求。

具体实例如下:

	//向前引用
	//(\\d\\d)\\1,代表字符串必须和匹配的第一组一样
	Pattern p = Pattern.compile("(\\d(\\d))\\2");
	String s = "122455";
	Matcher m = p.matcher(s);
	while(m.find()) {
		System.out.println(m.group(1));
	}

总结:

    正则表达式,不仅仅应用在java的编程中,在其他的语言中也同样可以使用。在其他的语言中在,正则表达式的思想基本上都是相同的,不同的就是方法不同而已。除了在编程上的应用外,还可以应用于其他的很多方面。比如在linux中查找某种类型的文件,或者是使用vim来查找某个特定的字符串。总之,正则表达式还是很有必要的学的。这篇文章仅仅是从java编程的角度来简单的介绍了一下正则表达式,仅仅供大家在java中使用正则表达式入门参考而已。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值