最近要在項(xiàng)目中做HTML解析,本想使用NekoHTML來(lái)解析,但看了下NekoHTML有點(diǎn)復(fù)雜,故采用了一種便捷,笨的方式來(lái)完成項(xiàng)目的要求. 正則表達(dá)式此時(shí)發(fā)揮了她巨大的威力,為我排憂解難,很快便完成了HTML解析工作.
在解析期間,研究了很多java正則表達(dá)式使用方法,頗得一些經(jīng)驗(yàn),不敢獨(dú)享,愿與大家共享.
-
java正則表達(dá)式通過(guò)java.util.regex包下的Pattern類與Matcher類實(shí)現(xiàn)(建議在閱讀本文時(shí),打開(kāi)java API文檔,當(dāng)介紹到哪個(gè)方法時(shí),查看java API中的方法說(shuō)明,效果會(huì)更佳).
Pattern類用于創(chuàng)建一個(gè)正則表達(dá)式,也可以說(shuō)創(chuàng)建一個(gè)匹配模式,它的構(gòu)造方法是私有的,不可以直接創(chuàng)建,但可以通過(guò)Pattern.complie(String regex)簡(jiǎn)單工廠方法創(chuàng)建一個(gè)正則表達(dá)式,
Java代碼示例:
Pattern p=Pattern.compile("\\w+");
p.pattern();//返回 \w+
-
pattern() 返回正則表達(dá)式的字符串形式,其實(shí)就是返回Pattern.complile(String regex)的regex參數(shù)
-
1.Pattern.split(CharSequence input)
Pattern有一個(gè)split(CharSequence input)方法,用于分隔字符串,并返回一個(gè)String[],我猜String.split(String regex)就是通過(guò)Pattern.split(CharSequence input)來(lái)實(shí)現(xiàn)的.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
String[] str=p.split("我的QQ是:456456我的電話是:0532214我的郵箱是:aaa@aaa.com");
-
結(jié)果:str[0]="我的QQ是:" str[1]="我的電話是:" str[2]="我的郵箱是:aaa@aaa.com"
-
2.Pattern.matcher(String regex,CharSequence input)是一個(gè)靜態(tài)方法,用于快速匹配字符串,該方法適合用于只匹配一次,且匹配全部字符串.
Java代碼示例:
Pattern.matches("\\d+","2223");//返回true
Pattern.matches("\\d+","2223aa");//返回false,需要匹配到所有字符串才能返回true,這里aa不能匹配到
Pattern.matches("\\d+","22bb23");//返回false,需要匹配到所有字符串才能返回true,這里bb不能匹配到
-
3.Pattern.matcher(CharSequence input)
說(shuō)了這么多,終于輪到Matcher類登場(chǎng)了,Pattern.matcher(CharSequence input)返回一個(gè)Matcher對(duì)象.
Matcher類的構(gòu)造方法也是私有的,不能隨意創(chuàng)建,只能通過(guò)Pattern.matcher(CharSequence input)方法得到該類的實(shí)例.
Pattern類只能做一些簡(jiǎn)單的匹配操作,要想得到更強(qiáng)更便捷的正則匹配操作,那就需要將Pattern與Matcher一起合作.Matcher類提供了對(duì)正則表達(dá)式的分組支持,以及對(duì)正則表達(dá)式的多次匹配支持.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.pattern();//返回p 也就是返回該Matcher對(duì)象是由哪個(gè)Pattern對(duì)象的創(chuàng)建的
-
4.Matcher.matches()/ Matcher.lookingAt()/ Matcher.find()
Matcher類提供三個(gè)匹配操作方法,三個(gè)方法均返回boolean類型,當(dāng)匹配到時(shí)返回true,沒(méi)匹配到則返回false
-
matches()對(duì)整個(gè)字符串進(jìn)行匹配,只有整個(gè)字符串都匹配了才返回true
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.matches();//返回false,因?yàn)閎b不能被\d+匹配,導(dǎo)致整個(gè)字符串匹配未成功.
Matcher m2=p.matcher("2223");
m2.matches();//返回true,因?yàn)閈d+匹配到了整個(gè)字符串
-
我們現(xiàn)在回頭看一下Pattern.matcher(String regex,CharSequence input),它與下面這段代碼等價(jià)
Pattern.compile(regex).matcher(input).matches()
-
lookingAt()對(duì)前面的字符串進(jìn)行匹配,只有匹配到的字符串在最前面才返回true
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.lookingAt();//返回true,因?yàn)閈d+匹配到了前面的22
Matcher m2=p.matcher("aa2223");
m2.lookingAt();//返回false,因?yàn)閈d+不能匹配前面的aa
-
find()對(duì)字符串進(jìn)行匹配,匹配到的字符串可以在任何位置.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("22bb23");
m.find();//返回true
Matcher m2=p.matcher("aa2223");
m2.find();//返回true
Matcher m3=p.matcher("aa2223bb");
m3.find();//返回true
Matcher m4=p.matcher("aabb");
m4.find();//返回false
-
5.Mathcer.start()/ Matcher.end()/ Matcher.group()
當(dāng)使用matches(),lookingAt(),find()執(zhí)行匹配操作后,就可以利用以上三個(gè)方法得到更詳細(xì)的信息.
start()返回匹配到的子字符串在字符串中的索引位置.
end()返回匹配到的子字符串的最后一個(gè)字符在字符串中的索引位置.
group()返回匹配到的子字符串
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("aaa2223bb");
m.find();//匹配2223
m.start();//返回3
m.end();//返回7,返回的是2223后的索引號(hào)
m.group();//返回2223
-
Mathcer m2=m.matcher("2223bb");
m.lookingAt();??//匹配2223
m.start();??//返回0,由于lookingAt()只能匹配前面的字符串,所以當(dāng)使用lookingAt()匹配時(shí),start()方法總是返回0
m.end();??//返回4
m.group();??//返回2223
-
Matcher m3=m.matcher("2223bb");
m.matches();??//匹配整個(gè)字符串
m.start();??//返回0,原因相信大家也清楚了
m.end();??//返回6,原因相信大家也清楚了,因?yàn)閙atches()需要匹配所有字符串
m.group();??//返回2223bb
-
說(shuō)了這么多,相信大家都明白了以上幾個(gè)方法的使用,該說(shuō)說(shuō)正則表達(dá)式的分組在java中是怎么使用的.
start(),end(),group()均有一個(gè)重載方法它們是start(int i),end(int i),group(int i)專用于分組操作,Mathcer類還有一個(gè)groupCount()用于返回有多少組.
Java代碼示例:
Pattern p=Pattern.compile("([a-z]+)(\\d+)");
Matcher m=p.matcher("aaa2223bb");
m.find();??//匹配aaa2223
m.groupCount();??//返回2,因?yàn)橛?組
m.start(1);??//返回0 返回第一組匹配到的子字符串在字符串中的索引號(hào)
m.start(2);??//返回3
m.end(1);??//返回3 返回第一組匹配到的子字符串的最后一個(gè)字符在字符串中的索引位置.
m.end(2);??//返回7
m.group(1);??//返回aaa,返回第一組匹配到的子字符串
m.group(2);??//返回2223,返回第二組匹配到的子字符串
-
現(xiàn)在我們使用一下稍微高級(jí)點(diǎn)的正則匹配操作,例如有一段文本,里面有很多數(shù)字,而且這些數(shù)字是分開(kāi)的,我們現(xiàn)在要將文本中所有數(shù)字都取出來(lái),利用java的正則操作是那么的簡(jiǎn)單.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
while(m.find()) {
????System.out.println(m.group());
}
-
輸出:
456456
0532214
123
-
如將以上while()循環(huán)替換成
while(m.find()) {
????System.out.println(m.group());
????System.out.print("start:"+m.start());
????System.out.println(" end:"+m.end());
}
則輸出:
456456
start:6 end:12
0532214
start:19 end:26
123
start:36 end:39
-
現(xiàn)在大家應(yīng)該知道,每次執(zhí)行匹配操作后start(),end(),group()三個(gè)方法的值都會(huì)改變,改變成匹配到的子字符串的信息,以及它們的重載方法,也會(huì)改變成相應(yīng)的信息.
注意:只有當(dāng)匹配操作成功,才可以使用start(),end(),group()三個(gè)方法,否則會(huì)拋出java.lang.IllegalStateException,也就是當(dāng)matches(),lookingAt(),find()其中任意一個(gè)方法返回true時(shí),才可以使用.
-
6.Matcher.
replaceAll
(
String
replacement) / Matcher.replaceFirst(String replacement)
大家應(yīng)該知道String.replaceAll()和String.replaceFirst()兩個(gè)方法的功能,其實(shí)它與Matcher.replaceAll()和Matcher.replaceFirst()的功能是一樣的,只不過(guò)是使用方式不一樣.例如我要將某文本中的所有數(shù)字變成*
使用String完成該要求
Java代碼示例:
String str="我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com";
System.out.println(str.replaceAll("\\d","*"));
?
輸出: 我的QQ是:****** 我的電話是:******* 我的郵箱是:aaa***@aaa.com
?
現(xiàn)在我們用Matcher完成該要求
Java代碼示例:
Pattern p=Pattern.compile("\\d");
-Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
System.out.println(m.replaceAll("*"));
?
輸出: 我的QQ是:****** 我的電話是:******* 我的郵箱是:aaa***@aaa.com
?
String.replaceAll()應(yīng)該是調(diào)用了Matcher.replaceAll(),String.replaceAll()與下面這段代碼等價(jià)
Pattern
.
compile
(
regex
).matcher
(
str
).replaceAll
(
replacement
)
?
至于Matcher.replaceFirst()也很簡(jiǎn)單,它與String.replaceFirst()功能一樣,我就不多說(shuō)了.
str
.replaceFirst(
regex
,
replacement
)與下面這段代碼等價(jià)
Pattern
.compile
(regex).matcher
(str).replaceFirst
(replacement)
?
7.Matcher.
appendReplacement
(
StringBuffer
sb,
String
replacement) / Matcher.appendTail(StringBuffer sb)
-將當(dāng)前匹配子串替換為指定字符串,并且將替換后的子串以及其之前到上次匹配子串之后的字符串段添加到一個(gè)StringBuffer對(duì)象里,而appendTai-l(StringBuffer sb) 方法則將最后一次匹配工作后剩余的字符串添加到一個(gè)StringBuffer對(duì)象里.看例子:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
StringBuffer sb=new StringBuffer();
m.find();? //匹配到456456
m.appendReplacement(sb,"*");? //將456456之前的字符串追加到sb,再將456456替換為*,并追加到sb
System.out.println(sb.toString());
m.appendTail(sb);? //將前面替換過(guò)的內(nèi)容連接后面未替換過(guò)的內(nèi)容,并放入sb
System.out.println(sb.toString());
?
輸出:
我的QQ是:*
我的QQ是:* 我的電話是:0532214 我的郵箱是:aaa123@aaa.com
?
再看一個(gè)例子
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
StringBuffer sb=new StringBuffer();
while(m.find()) {
??? m.appendReplacement(sb,"*");
??? System.out.println(sb.toString());
}
m.appendTail(sb);
System.out.println("使用appendTail()的最終內(nèi)容是:"+sb.toString());
?
輸出:
我的QQ是:*
我的QQ是:* 我的電話是:*
我的QQ是:* 我的電話是:* 我的郵箱是:aaa*
使用appendTail()的最終內(nèi)容是:我的QQ是:* 我的電話是:* 我的郵箱是:aaa*@aaa.com
?
關(guān)于這兩個(gè)方法就介紹到這,如果不明白的話,還需要自己動(dòng)下手,認(rèn)真體會(huì)一下其內(nèi)涵.
?
-8.Matcher.region
(int?start, int?end) / Matcher.regionEnd() / Matcher.regionStart()
我們?cè)谧銎ヅ洳僮鲿r(shí),默認(rèn)去匹配的是整個(gè)字符串,例如有一字符串"aabbcc",使用"\\d+"去find()時(shí),是從第一個(gè)a開(kāi)始匹配,也就是索引號(hào)為0的位置,開(kāi)始去匹配,當(dāng)索引號(hào)為0的位置沒(méi)有匹配到時(shí),就去下一個(gè)位置去匹配...直到匹配到子字符串或匹配完最后一個(gè)字符索引號(hào)才結(jié)束,很顯然"\\d+"不能匹配"aabbcc",當(dāng)它匹配完最后一個(gè)c時(shí),結(jié)束本次匹配,宣告匹配失敗,也就是說(shuō)它會(huì)去匹配完整個(gè)字符串,能不能不去匹配完整個(gè)字符串呢,答案是可以的.
region(int start,int end)就是用來(lái)設(shè)置此匹配器的區(qū)域限制。
先來(lái)看一個(gè)例子.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
String content="aaabb2233cc";
Matcher m=p.matcher(content);
System.out.println(m);
?
輸出: java.util.regex.Matcher[pattern=\d+ region=0,11 lastmatch=]
?
可以看到region=0,11 表示start=0,end=11,更通俗的說(shuō)就是當(dāng)去匹配字符串,先從索引號(hào)為0的位置去匹配,如果匹配到了子字符串就返回,如果沒(méi)有匹配到則到下一個(gè)位置去匹配,一直匹配到索引號(hào)為11-1的字符就結(jié)束匹配.
為什么是11呢,因?yàn)閏ontent.length()==11
現(xiàn)在你應(yīng)該明白了它的作用,來(lái)看一個(gè)例子.
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
String content="aaabb2233cc";
Matcher m=p.matcher(content);
m.find();? //匹配到2223,返回true
?
Matcher m2=p.matcher(content);
m2.region(0,5);
m2.find();? //返回false,只去匹配索引號(hào)0至5-1的字符,沒(méi)有匹配到
?
Matcher m3=p.matcher(content);
m2.region(3,8);
m2.find();? //返回true
m2.group();? //返回223,為什么,請(qǐng)數(shù)一下索引號(hào)就知道了.
?
Matcher.regionStart()返回region(int start,int end)中的start值,默認(rèn)為0
Matcher.regionEnd()返回region(int start,int end)中的end值,默認(rèn)為去匹配字符串的length()值
9.Matcher.
reset
() / Matcher.reset(CharSequence?input)
用于重置匹配器。看示例
Java代碼示例:
Pattern p=Pattern.compile("[a-z]+");
String content="aaabb2233cc";
Matcher m=p.matcher(content);? //此時(shí)m剛創(chuàng)建出來(lái),為最初狀態(tài)
m.find();
m.group();? //返回aaabb
m.find();
m.group();? //返回cc
?
Matcher m2=p.matcher(content);? //此時(shí)m2剛創(chuàng)建出來(lái),為最初狀態(tài)
m.find();
m.group();? //返回aaabb
m.reset();? //恢復(fù)到了最初狀態(tài),此時(shí)相當(dāng)于m2剛創(chuàng)建出來(lái)
m.find();
m.group();? //返回aaabb,相信大家應(yīng)該知道了吧
?
?Matcher.reset(CharSequence?input) 恢復(fù)到最初狀態(tài),并將匹配字符串換成input,以后執(zhí)行匹配操作時(shí),就來(lái)匹配input,而不匹配原來(lái)的字符串了.
?
10.Matcher.toMatchResult
()
大家查看一下java API 對(duì)Matcher類的說(shuō)明,會(huì)發(fā)現(xiàn)它實(shí)現(xiàn)了MatchResult 接口,這個(gè)接口只有以下幾個(gè)方法
groupCount()?
group() / group(int i)
start() /?start(int i)
end() / end(int i)
?
至于這幾個(gè)方法的功能前面已經(jīng)介紹過(guò),現(xiàn)在我們來(lái)看一下toMatchResult() 是如何使用的
Java代碼示例:
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
List list=new ArrayList();
while(m.find()) {
??? list.add(m.toMatchResult());
}
MatchResult matchResult=null;
Iterator it=list.iterator();
int i=1;
while(it.hasNext()) {
??? matchResult=(MatchResult)it.next();
??? System.out.print("第"+(i++)+"次匹配到的信息: ");
??? System.out.println(matchResult.group()+"\t\t"+matchResult.start()+"\t"+matchResult.end());
}
?
輸出:
第1次匹配到的信息: 456456????????? ?6????? ? 12
第2次匹配到的信息: 0532214??????? 19??? ??26
第3次匹配到的信息: 123??????????????? ?36??? ??39
?
現(xiàn)在你應(yīng)該知道,toMatchResult()用于保存某次匹配后的信息,待以后再使用.
方法使用就說(shuō)到這里,現(xiàn)在再介紹一個(gè)實(shí)例
-
有這樣一個(gè)需求,有一個(gè)HTML文件,需要將其中的內(nèi)容抽取出來(lái),并不帶HTML標(biāo)簽,如果使用正則表達(dá)式,這是一件很容易的事情. 前提是這個(gè)HTML文件只保留了<body></body>標(biāo)簽以內(nèi)的內(nèi)容.
Java代碼示例:
String html="<div><font? color='red'>example1</font></div>"; //可以是任何html文件源代碼,但格式一定要正確
Pattern p=Pattern.compile("<[^>]*>");
Matcher m=p.matcher(html);
String result=m.replaceAll("");
System.out.println(result);
-
輸出:example1?
參考資料:
java.util.regex的API文檔
陳廣佳的JAVA正則表達(dá)式--Pattern和Matcher
posted on 2007-12-15 12:19
crazy 閱讀(576)
評(píng)論(0) 編輯 收藏 所屬分類:
java