java正则表达式

学习连接: http://www.ibeifeng.com/ http://bbs.langsin.com/viewthread.php?tid=8092&extra=&page=1

RegularExpressions

正则表达式

字符串的处理利器

正则表达式是在Unix上流行起来的

peolperl语言对正则表达式的处理好

太有用了

IP地址是否正确

可以作为大多数网站的验证

从网页里揪出email地址

可以发垃圾邮件

从网页中揪出链接等

就像迅雷抓取页面似的

字符串里有个方法java.lang.String

boolean matches(String regex)

regex是正则表达式,正则表达式本身也是一个字符串,只不过是一个特殊的字符串


<!--[endif]-->

运行结果:

true

三个点是什么?

一个点代表一个字符


<!--[endif]-->


<!--[endif]-->

数字都变成—了

d代表一位数字

用两个//代表一个/

Pattern,我们大多数要参考这个类

static Pattern compile(String regex)

什么意思呢?

将正则表达式编译一下,编译之后放到Pattern模式里边

Pattern所代表的就是字符串所要匹配的模式,而这个模式本身需要编译一下的

为什么要编译呢?

如果你不编译,每次现场编译的时候速度就会慢一点

你首先将这个模式编译好了,再拿这个模式去匹配字符串的时候,匹配起来的速度就会快一些

[a-z]匹配一位字母

[a-z]{3}匹配具有三位字母的字符串,并且这三个字符必须是az之间的

public Matcher matcher(CharSequence input)

matcher意思是说我要去匹配某一个字符串

CharSequence字符序列

字符串本身实现了CharSequence接口

这里又是多态,父类引用指向子类对象

Matcher叫匹配器

实际上背后的内部原理是这样的

他会创建一个有限状态的自动机

简单理解就是p是一种模式

这种模式匹配那个字符串

在匹配过程中可能会产生多个结果

产生的结果保留在Matcher对象m

打印出结果

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

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

Matcher m = p.matcher(“fgh”);

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

三句写成一句就是

System.out.println(“fgh”.matches(“[a-z]{3}”))

字符串 正则表达式

为什么不写成一句呢?

三句的效率高些,并且PatternMatcher提供了其他很多很重要的功能

初步认识MetaCharacters . * +

meta的源数据意思

. 是一个字符的意思

* 0个或多个

+ 表一个或多个

表一个或0

在正则表达式里也有正常的字符,并不是所有的都是非正常的

X{n} X正好出现n

X{n,} X至少出现n

X{n,m} X至少出现n次,最多出现m

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

数字出现13

.是特殊字符,用//.表示

[ ]表示范围

p("".matches("a?")); 返回结果是true

""空串表示a出现0次或一次,在英文里叫zero length 零宽度匹配

p("".matches("a*")) 同理

范围

[abc]

[]表达的意思是去[]中字符的某一个就可以了,匹配一个字符,不管有多长

p("a".matches("[abc]"));表示请你取abc中的一个看有没有和a匹配的

p("a".matches("[^abc]"));表示取除了abc以外的其他字符都可以

p("A".matches("[a-zA-Z]"));表示取a-z或者A-Z

p("A".matches("[a-z]|[A-Z]"));和上面的一样

p("A".matches("[a-z[A-Z]]"));和上面的一样

p("R".matches("[A-Z&&[RFG]]"));表示A-Z 中的并且要RFG三个中的

取并集

认识其他MetaCharacters /s /w /d /

/s表示空白字符,空白字符包含什么了?[ /t /n /x0B /f /r]

空格 tab键 换行 制表符 回车

/w表示[a-zA-Z_0-9]构成单词的字符

有时候需要取用户名,可以用这种正则表达式取出来

<!--[endif]-->

如果写成一个反斜杠/就会报错,因为/和后面的“构成转义字符

p("//".matches("//"));报错

正则表达式本身要匹配一个表达式的话需要两个反斜杠

用字符串把一个正则表达式表现出来的时候

每一个反斜线都要用两个反斜杠替代

如果写两个//

p("//".matches("//"));中的后一反斜杠会和“匹配成转义字符,这样就必须用四个/

p("//".matches(""));

POSIXUnix操作系统的一套标准,用的不是特别多

边界匹配

p("hello sir".matches("^h.*"));表示开头第一个字母为h,.一个字符,后面跟着0个或多个字符

^ 是什么意思?

位于[]第一字符意思是取反,在[]外表示一行的起始位置

p("hello sir".matches(".*ir$"));

$以什么结尾,这里表示亿ir结尾

/b是单词的边界

什么是单词边界

空白字符,换行,各种各样的特殊字符等等都算边界字符

p("hello sir".matches("^h[a-z]{1,3}o//b.*"));//true

p("hellosir".matches("^h[a-z]{1,3}o//b.*"));//false

找文档里的空白行,怎么找呢?

p(" /n".matches("^[//s&&[^//n]]*//n$"));

开头是空白符,并且不是换行符,出现0次或1次,最后以换行符结束

测试:

p("aaa 8888c".matches(".*//d{4}."));//true

p("aaa 8888c".matches(".*//b//d{4}."));//true

email

p("asdfasdfsafsf@dsdfsdf.com".matches("[//w[.-]]+@[//w[.-]]+//.[//w]+"));

这是一般的匹配email的方法

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

String s = "123-34345-234-00";

Matcher m = p.matcher(s);//用那个模板匹配字符串

p(m.matches());//匹配整个字符串

m.reset();//吃进去还吐出来

p(m.find());//表示找一个和那个模式相匹配的子串

p(m.start() + "-" + m.end());

p(m.find());//当找到一个子串后,他会把这个子串去掉,然后从剩下的字符串里再找

p(m.start() + "-" + m.end());//end是找到的最后一个位置的后一个位置

p(m.find());

p(m.start() + "-" + m.end());

p(m.find());

//p(m.start() + "-" + m.end());字符串只有能被找到才能输出起始位置,否则报错

p(m.lookingAt());//意思是每次找的时候从第一个字符的位置开始找

p(m.lookingAt());//每次都是从开头位置找

p(m.lookingAt());

p(m.lookingAt());

字符串的替换replacement

m.group()输出匹配到的那个子串

static Pattern compile(String regex, int flags)

flags意思是可以指定一些常量用来规定编译时的规则

Pattern p = Pattern.compile("java",Pattern.CASE_INSENSITIVE);

忽略大小写

将找到的字符串,奇数位替换成大写,偶数位替换成小写

Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf");

StringBuffer buf = new StringBuffer();

int i=0;

while(m.find()) {

i++;

if(i%2 == 0) {

.appendReplacement(buf, "java");//意思是添加一个用来做替换的,替换的找得这个位置

} else {

m.appendReplacement(buf, "JAVA");

}

}

m.appendTail(buf);//这个是为了防止最后那段字符串丢掉

p(buf);

分组

group

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

String s = "123aa-34345bb-234cc-00";

Matcher m = p.matcher(s);

while(m.find()) {

p(m.group());

}

结果:

把符合上面那个正则表达式的子串中的数字拿出来?

怎么拿?

用循环太麻烦。。

这里用分组来实现

分组用小括号构成的

分了几组就看有几对小括号

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

其实算上整个大组是分了2

p(m.group(1);意思是符合第一组的子串

怎么确定那个是第一组呢

只要数每对小括号的左小括号就可以了

以后我们揪email的时候,只想把@前的名字揪出来,该怎么办呢?

用分组的办法

**************************************************************************************************************************************************************

抓取网页中的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;

public class EmailSpider {

public static void main(String[] args) {

try {

BufferedReader br = new BufferedReader(new FileReader("D://share//courseware//1043633.html"));

String line = "";

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

parse(line);

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

private static void parse(String line) {

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

Matcher m = p.matcher(line);

while(m.find()) {

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

}

}

}

**************************************************************************************************************************************************************

代码统计小程序

当拿到文件以后,检测文件的后缀名

如何检验每个文件的后缀名?

专业的程序员应该将comment == true 写成 true == comment

他们的区别是什么?

readLine方法,取出一行后本身已经将换行符去掉了

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

public class CodeCounter {

static long normalLines = 0;//有效代码

static long commentLines = 0;//注释代码数量

static long whiteLines = 0;//空白行

public static void main(String[] args) {

File f = new File("D://share//JavaProjects//TankWar1.9.11//src");

File[] codeFiles = f.listFiles();

for(File child : codeFiles){

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

parse(child);

}

}

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

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

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

}

private static void parse(File f) {

BufferedReader br = null;

boolean comment = false;//用来循环统计注释里的代码数

try {

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

String line = “”;

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

line = line.trim();//避免要是一行开头是以tal键开始的怎么办

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();

}

}

}

}

}

**************************************************************************************************************************************************************

以上基本上可以解决一般的正则表达式了

但是正则表达式还有一些深层次的写法

要是见了不认识也是一种遗憾

//qulifiers修饰符 限定符

Greedy quantifiers 贪婪的

Reluctant quantifiers 勉强的,不情愿的

Possessive quantifiers 独占性的

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

String s = "aaaa5bbbb6";

Matcher m = p.matcher(s);

if(m.find())

p(m.start() + "-" + m.end());

else

p("not match!");

310个字符后面跟一个数字

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

显示的结果是0-5

greedy的意思是说 Pattern p = Pattern.compile("(.{3,10} ) [0-9]");

当他看到.{3,10}的时候,他最多是10个字符

那么他二话不说先吞10字符再说

干活比较贪婪,不是挑最少的,而是挑最多的直接吞下去

吞下的10个字符和正则表达式.{3,10}做匹配

这里匹配不上

匹配不上就往外吐一个,并把这个6作为正则表达式的数字的话真好匹配[0-9]

那么剩下的aaaa5bbbb也真好匹配.{3,10}

Reluctant意思是 Pattern p = Pattern.compile("(.{3,10}? ) [0-9]");

上来不是吃最多的,而是最少的

上来先吃3个匹配.{3,10}

后面的不是数字

然后再吞一个

后面的是数字了,匹配[0-9]

到此为止

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

和贪婪的有点类似

直接将字符都吞进来

但是不忘外吐

这样就没有能匹配了

这里输出 not match

换成字符String s = "aaaa5bbbb6";就可以匹配了

0-11

**************************************************************************************************************************************************************

补充

可能会在论坛里遇到的写法

可以不会写但要能看懂别人写的

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

String s = "444a66b";

Matcher m = p.matcher(s);

while(m.find()) {

p(m.group());

}

结果是

44a

66b

non-capturing

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

String s = "444a66b";

Matcher m = p.matcher(s);

while(m.find()) {

p(m.group());

}

.{3}(?=a)什么意思呢?

小括号正常情况下是一个组,这个组是用来匹配字符串的

如果是以括号里?打头的他不是来匹配字符串的

所以叫非捕获字符串

这里表示抓取字符串里前三个是字符紧跟一个a

但是a不被捕获

也就是不输出a

最后结果是444

(?=a).{3} 写成这样的结果是

a66

比较诡异

(?!a).{3} 意思是前面不能是a

输出结果是

444

66b

.{3} (?!a) 意思是

结果是44a

66b

他首先找444后面是a

那么他继续往后找,也就是往后推一个

44a

**************************************************************************************************************************************************************

back refenrences

向前引用

Pattern p = Pattern.compile("(//d//d)//1");

String s = "1212";

Matcher m = p.matcher(s);

p(m.matches());

//d//d找两个数字

//1的意思是后面找到的结果必须和我前面第一个group找到的一样

Pattern p = Pattern.compile("(//d(//d))//2");

String s = "122";

Matcher m = p.matcher(s);

p(m.matches());

**************************************************************************************************************************************************************

flags的简写

//Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE);

简写

p("Java".matches("(?i)(java)"));

?i这里叫非捕获组non-capturing

**************************************************************************************************************************************************************

关于正则表达式的,用不着专门买书来研究,有不懂得就上网问

code

import java.util.regex.Matcher; import java.util.regex.Pattern; public class Test { public static void main(String[] args) { //简单认识正则表达式的概念 /* p("abc".matches("...")); p("a8729a".replaceAll("//d", "-")); Pattern p = Pattern.compile("[a-z]{3}"); Matcher m = p.matcher("fgh"); p(m.matches()); p("fgha".matches("[a-z]{3}")); */ //初步认识. * + ? /* p("a".matches(".")); p("aa".matches("aa")); p("aaaa".matches("a*")); p("aaaa".matches("a+")); p("".matches("a*")); p("aaaa".matches("a?")); p("".matches("a?")); p("a".matches("a?")); p("214523145234532".matches("//d{3,100}")); p("192.168.0.aaa".matches("//d{1,3}//.//d{1,3}//.//d{1,3}//.//d{1,3}")); p("192".matches("[0-2][0-9][0-9]")); */ //范围 /* p("a".matches("[abc]")); p("a".matches("[^abc]")); p("A".matches("[a-zA-Z]")); p("A".matches("[a-z]|[A-Z]")); p("A".matches("[a-z[A-Z]]")); p("R".matches("[A-Z&&[RFG]]")); */ //认识/s /w /d / /* p(" /n/r/t".matches("//s{4}")); p(" ".matches("//S")); p("a_8".matches("//w{3}")); p("abc888&^%".matches("[a-z]{1,3}//d+[&^#%]+")); p("//".matches("")); */ //POSIX Style //p("a".matches("//p{Lower}")); //boundary /* p("hello sir".matches("^h.*")); p("hello sir".matches(".*ir$")); p("hello sir".matches("^h[a-z]{1,3}o//b.*")); p("hellosir".matches("^h[a-z]{1,3}o//b.*")); //whilte lines p(" /n".matches("^[//s&&[^//n]]*//n$")); p("aaa 8888c".matches(".*//d{4}.")); p("aaa 8888c".matches(".*//b//d{4}.")); p("aaa8888c".matches(".*//d{4}.")); p("aaa8888c".matches(".*//b//d{4}.")); */ //email //p("asdfasdfsafsf@dsdfsdf.com".matches("[//w[.-]]+@[//w[.-]]+//.[//w]+")); //matches find lookingAt /* Pattern p = Pattern.compile("//d{3,5}"); String s = "123-34345-234-00"; Matcher m = p.matcher(s); p(m.matches()); m.reset(); p(m.find()); p(m.start() + "-" + m.end()); p(m.find()); p(m.start() + "-" + m.end()); p(m.find()); p(m.start() + "-" + m.end()); p(m.find()); //p(m.start() + "-" + m.end()); p(m.lookingAt()); p(m.lookingAt()); p(m.lookingAt()); p(m.lookingAt()); */ //replacement /* Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); Matcher m = p.matcher("java Java JAVa JaVa IloveJAVA you hateJava afasdfasdf"); StringBuffer buf = new StringBuffer(); int i=0; while(m.find()) { i++; if(i%2 == 0) { m.appendReplacement(buf, "java"); } else { m.appendReplacement(buf, "JAVA"); } } m.appendTail(buf); p(buf); */ //group /* Pattern p = Pattern.compile("(//d{3,5})([a-z]{2})"); String s = "123aa-34345bb-234cc-00"; Matcher m = p.matcher(s); while(m.find()) { p(m.group()); } */ //qulifiers /* Pattern p = Pattern.compile(".{3,10}+[0-9]"); String s = "aaaa5bbbb68"; Matcher m = p.matcher(s); if(m.find()) p(m.start() + "-" + m.end()); else p("not match!"); */ //non-capturing groups /* Pattern p = Pattern.compile(".{3}(?=a)"); String s = "444a66b"; Matcher m = p.matcher(s); while(m.find()) { p(m.group()); } */ //back refenrences /* Pattern p = Pattern.compile("(//d(//d))//2"); String s = "122"; Matcher m = p.matcher(s); p(m.matches()); */ //flags的简写 //Pattern p = Pattern.compile("java", Pattern.CASE_INSENSITIVE); p("Java".matches("(?i)(java)")); } public static void p(Object o) { System.out.println(o); } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值