手机
当前位置:查字典教程网 >编程开发 >Java >Java的正则表达式深入分析
Java的正则表达式深入分析
摘要:一.regex(正则表达式):RegularExpressions(代替了StringTokenizer);字符串处理利器;在unix流行,...

一.regex(正则表达式):RegularExpressions(代替了StringTokenizer);字符串处理利器;在unix流行,perl使用regex更牛。

主要用在字符串匹配、查找和替换。例如:匹配IP(范围小于256)使用正则很好搞;从网页中揪出大量email地址发送垃圾邮件;从网页里揪出链接。包含Matcher(用模式匹配字符串后产生的结果)和pattern。

复制代码 代码如下:

/*

* 告知此字符串是否匹配给定的正则表达式(也是一个字符串)。

*/

System.out.println("abc".matches("..."));//每个"."表示一个字符

复制代码 代码如下:

/*

* 把字符串里的所有数字替换成"-",普通方法需要charAt逐个判断;

* "d"表示任意一个数字或者换成"[0-9]";

* "D"表示任意一个非数字或者换成"[^0-9]"

*/

System.out.println("ab54564654sbg48746bshj".replaceAll("[0-9]", "-"));//每个"."表示一个字符

二、

复制代码 代码如下:

/*

* compile将给定的正则表达式编译到模式中(每次编译需要费时间);{3}表示恰好三次。

* X{n} X,恰好 n 次

* X{n,} X,至少 n 次

* X{n,m} X,至少 n 次,但是不超过 m 次

*/

Pattern p = Pattern.compile("[a-z]{3}");

Matcher m = p.matcher("ggs");//创建匹配给定输入与此模式的匹配器。内部实际上是创建了一个优先状态的自动机(编译原理)

//matcher和matches里待匹配的字符串实际上是CharSequence(接口),不过String实现了该接口,存在多态

System.out.println(m.matches());//若是"ggss"就不匹配了

//可一直接"ggs".matches("[a-z]{3}"),不过上面的有好处,至少效率高了,而且Pattern和Matcher提供了很多功能

三、在regex“. * +”中叫Meta Character;ctrl + shift + "/"表示注释,换成""表示去掉注释。

复制代码 代码如下:

"a".matches(".");//true,"."表示任意一个字符,汉字也行

"aa".matches("aa");//true,也就是说普通字符串也可以作为正则表达式

/*

* true,"*"表示0或者多个字符,不过后面的要和第一个相同,

* 否则false,也就是判断字符串是否是单一字符组成的字符串

*/

"aaaa".matches("a*");

"".matches("a*");//true

"aaa".matches("a?");//true,一次或者0次

"".matches("a?");//true

"a".matches("a?");//true

"544848154564113".matches("d{3,100}");//true

//这个是最简单的IP判断,不过若是超过255则判断不出来

"192.168.0.aaa".matches("d{1,3}.d{1,3}.d{1,3}d{1,3}");

"192".matches("[0-2][0-9][0-9]");

四、[abc]表示匹配任意一个字符;[^abc]表示出了abc以外的其他字母(必须还是字母,若是空串也返回false)字符;[a-zA-Z]等价于"[a-z]|[A-Z]"是否是某个大小写字母;[A-Z&&[ABS]]表示大写字母中取ABS中任一个。

复制代码 代码如下:

//发现|和||没区别,&和&&有区别,不知道这么理解对不对

System.out.println("C".matches("[A-Z&&[ABS]]"));//false

System.out.println("C".matches("[A-Z&[ABS]]"));//true

System.out.println("A".matches("[A-Z&&[ABS]]"));//true

System.out.println("A".matches("[A-Z&[ABS]]"));//true

System.out.println("C".matches("[A-Z|[ABS]]"));//true

System.out.println("C".matches("[A-Z||[ABS]]"));//true

五、w 单词字符:[a-zA-Z_0-9] 进行用户名匹配时;s 空白字符:[ tnx0Bfr]; S 非空白字符:[^s] ;W 非单词字符:[^w] 。

复制代码 代码如下:

" ntr".matches("s{4}");//true

" ".matches("S");//false

"a_8".matches("w{3}");//true

//“+”表示一次或者多次

"abc888&^%".matches("[a-z]{1,3}d+[&^#%]+");//true

/*

* 待匹配字符也只是一个反斜线,不过不可写成""那么和后面的"组合了,

* 前面的"无法匹配就会CE。

* 后面不可写成"",那么会运行错误(编译没问题),必须写成""

*/

System.out.println("".matches(""));//true

六、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] 。

七、边界匹配器

^ 行的开头

$ 行的结尾

b 单词边界

B 非单词边界

A 输入的开头

G 上一个匹配的结尾

Z 输入的结尾,仅用于最后的结束符(如果有的话)

z 输入的结尾

复制代码 代码如下:

"hello world".matches("^h.*");//^行的开头

"hello world".matches(".*ld$");//$行的结尾

"hello world".matches("^h[a-z]{1,3}ob.*");//b单词边界

"helloworld".matches("^h[a-z]{1,3}ob.*");

" n".matches("^[s&&[^n]]*n$");//判断空白行,空白行开头是空白符

八、还可以在find方法下使用m.start()和m.end()返回开始位置和结束位置的下一个;若是找不到则出错。

复制代码 代码如下:

Pattern p = Pattern.compile("d{3,5}");

String s = "133-34444-333-00";

Matcher m = p.matcher(s);

m.matches();//matches匹配全部字符串

m.reset();

/*

* 下面若是先调用了reset方法则输出true,true,true,false.

* 否则倒数第二个find也输出false。

* 原因如下:

* matches匹配到第一个"-"发现不匹配了,但是这四个字符已经被吃掉啦,再次匹配就从

* 34444开始了,第二个find从333,因为find匹配的是下一个子序列。

* reset方法让matches吃掉的字符串再吐出来。

* 综上:matches和find之间要使用reset,因为二者相互影响

*

*/

m.find();

m.find();

m.find();//尝试查找与该模式匹配的输入序列的下一个子序列

m.find();

/*

* 尝试将从区域开头开始的输入序列与该模式匹配。

* Thinking in java的作者狠狠滴批评了这个方法,因为从字面看不出来到底从哪开始匹配。

* 下面全部是true,因为每次都从头开始

*/

m.lookingAt();

m.lookingAt();

m.lookingAt();

m.lookingAt();

九、字符串替换

复制代码 代码如下:

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class TestRegexReplacement {

public static void main(String[] args) {

Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);//后面的参数是整形,表示“大小写不敏感”

Matcher m = p.matcher("Java java hxsyl Ilovejava java JaVaAcmer");

while(m.find()) {

System.out.println(m.group());//m.group会输出所有的java(忽略大小写)

}

String s = m.replaceAll("Java");//String也有该方法

System.out.println(s);

m.reset();//一定要加,因为find和matcher相互影响

StringBuffer sb = new StringBuffer();

int i = 0;

/*

* 下面的方法是把找到的奇数个java替换为“Java”,偶数个替换成"java"

*/

while(m.find()) {

i++;

//不能直接写成i&1必须转化为boolean

if((i&1)==1) {

m.appendReplacement(sb, "Java");

}else {

m.appendReplacement(sb, "java");

}

}

m.appendTail(sb);//把找到的最后一个java后边的剩余字符串加上

System.out.println(sb);//不加reset的话只输出了Acmer

}

}

十、分组

复制代码 代码如下:

/*

* 分别加上小括号,不算最外边的大括号,第一个左括号便是第一组

*/

Pattern p = Pattern.compile("(d{3,5})([a-z]{2})");

String s = "123aaa-77878bb-646dd-00";

Matcher m = p.matcher(s);

while(m.find()) {

System.out.println(m.group());

System.out.println(m.group(1));//输出每对符合的 数字

System.out.println(m.group(2));//输出每对符合的 字母

}

十一、抓取网页中的email

复制代码 代码如下:

import java.io.BufferedReader;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/*

* 需要什么养的方法的话先些方法名

* 然后ctrl + 1列出推荐,系统创建该方法

*/

public class EmailSpider {

public static void main(String[] args) {

// TODO Auto-generated method stub

try {

BufferedReader br = new BufferedReader(new FileReader("F:regex.html"));

String line = "";

try {

while((line=br.readLine())!=null) {

solve(line);

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private static void solve(String line) {

// TODO Auto-generated method stub

//正则表达式要是不满足相应功能的话不会出错,因为他是字符串

Pattern p = Pattern.compile("[w[.-]]+@[w[.-]]+.[w]+");

Matcher m = p.matcher(line);

while(m.find()) {

System.out.println(m.group());

}

}

}

十二、代码统计

复制代码 代码如下:

View Code

/*

* 统计代码里多少空行,注释行,程序行

* 实际上使用String里的startsWith和endsWith也行.

* 若是项目经理用的话还要统计每行的字符数是否以{;结尾,防止偷懒

*/

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

public class CoderCount {

static long normalLines = 0;

static long commentLines = 0;

static long whiteLines = 0;

public static void main(String[] args) {

File f = new File("D:sharesrc");

File[] codeFiles = f.listFiles();

for(File child : codeFiles){

if(child.getName().matches(".*.java$")) {

solve(child);

}

}

System.out.println("normalLines:" + normalLines);

System.out.println("commentLines:" + commentLines);

System.out.println("whiteLines:" + whiteLines);

}

private static void solve(File f) {

BufferedReader br = null;

boolean comment = false;

try {

br = new BufferedReader(new FileReader(f));

String line = "";

while((line = br.readLine()) != null) {

/*

* //有的注释行前面有一个tab

* 不可写在readLine后

* 最后一行的话会空指针

*/

line = line.trim();

//readLine读出字符串后就把后面的换行去掉啦

if(line.matches("^[s&&[^n]]*$")) {

whiteLines ++;

} else if (line.startsWith("/*") && !line.endsWith("*/")) {

commentLines ++;

comment = true;

} else if (line.startsWith("/*") && line.endsWith("*/")) {

commentLines ++;

} else if (true == comment) {

commentLines ++;

if(line.endsWith("*/")) {

comment = false;

}

} else if (line.startsWith("//")) {

commentLines ++;

} else {

normalLines ++;

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if(br != null) {

try {

br.close();

br = null;

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

十三、Quantifiers

包括?*+;默认全是Greedy,还有Reluctant和Possessive(独占性的)。

复制代码 代码如下:

//加上分组是为了看得更清晰一些

Pattern p = Pattern.compile("(.{3,10})+[0-9]");

String s = "aaaa5bbbb6";//长度是10

Matcher m = p.matcher(s);

/*

* 现在输出0-10,默认是Greedy,先吞进10个字符,发现不匹配,吐出来一个,发现匹配了;

* 若是Pattern.compile("(.{3,10}?)+[0-9]")则成了Reluctant,那么是先吞进三个字符,发现不匹配,继续吞入 知道匹配,输出0到5;

* 若是Pattern.compile("(.{3,10}++)+[0-9]")则是Possessive(独占式),也是先吞入10个字符,但是不向外吐,那么就不匹配了,

* 这种方式主要用在需要高效率的地方(会有误差)。

*/

if(m.find()) {

System.out.println(m.start() + "----" + m.end());

}else {

System.put.println("Not match!");

}

十四、补充(非捕获组)

复制代码 代码如下:

//非捕获组的意思和字面相反,意思是若是符合则捕获

Pattern p = Pattern.compile("(?=a).{3}");

/*

* 输出a66,相当于要求以a开头,也可以这么写Pattern.compile("[a].{2}");

* 若是Pattern.compile(".{3}(?!=a)")不是不以a结尾{2}[^a],而是下一个字符不是a(lookahead),输出44a,66b,所以这种用法不常用;

* 若是Pattern.compile(".{3}(?=a)")则输出444(因为?=a是lookahead),放在前面则包含在组内,后面则不包含在组内;

*

*

*/

String s = "444a66b";

Matcher m = p.matcher(s);

while(m.find()) {

System.out.println(m.group());

}

十五、Back Reference

复制代码 代码如下:

Pattern p = Pattern.compile("(dd)1");

/*

* 输出true,1表示和第一个组的一样,若改成1213就不对了;

* 若是Pattern.compile("(d(d))2")则需改成122才对

*

*/

String s = "1212";

Matcher m = p.matcher(s);

System.out.println(m.matches());

十六、flags的简写

"."是不匹配换行的,记住CASE_INSENSITIVE就行了,简写“通过嵌入式标志表达式 (?i) 也可以启用不区分大小写的匹配”。

【Java的正则表达式深入分析】相关文章:

Java中CyclicBarrier的用法分析

深入分析Java内存区域的使用详解

java中的快捷键小结

Java for循环的几种用法分析

Java UrlRewriter伪静态技术运用深入分析

Java NIO工作原理的全面分析

基于JavaCore文件的深入分析

Java事务的个人理解小结

关于国际化、OGNL表达式语言

深入同步访问共享的可变数据分析

精品推荐
分类导航