本篇內(nèi)容介紹了“java正則表達(dá)式的實(shí)例用法”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
專注于為中小企業(yè)提供成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)江陵免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
Java正則表達(dá)式實(shí)例詳解
創(chuàng)建正則表達(dá)式
你可以從比較簡(jiǎn)單的東西入手學(xué)習(xí)正則表達(dá)式。要想全面地掌握怎樣構(gòu)建正則表達(dá)式,可以去看JDK文檔的java.util.regex的Pattern類的文檔。 字符
B 字符B
xhh 16進(jìn)制值0xhh所表示的字符
uhhhh 16進(jìn)制值0xhhhh所表示的Unicode字符
t Tab
n 換行符
r 回車符
f 換頁(yè)符
e Escape
正則表達(dá)式的強(qiáng)大體現(xiàn)在它能定義字符集(character class)。下面是一些最常見(jiàn)的字符集及其定義的方式,此外還有一些預(yù)定義的字符集: 字符集
. 表示任意一個(gè)字符
[abc] 表示字符a,b,c中的任意一個(gè)(與a|b|c相同)
[^abc] 除a,b,c之外的任意一個(gè)字符(否定)
[a-zA-Z] 從a到z或A到Z當(dāng)中的任意一個(gè)字符(范圍)
[abc[hij]] a,b,c,h,i,j中的任意一個(gè)字符(與a|b|c|h|i|j相同)(并集)
[a-z&&[hij]] h,i,j中的一個(gè)(交集)
s 空格字符(空格鍵, tab, 換行, 換頁(yè), 回車)
S 非空格字符([^s])
d 一個(gè)數(shù)字,也就是[0-9]
D 一個(gè)非數(shù)字的字符,也就是[^0-9]
w 一個(gè)單詞字符(word character),即[a-zA-Z_0-9]
W 一個(gè)非單詞的字符,[^w]
如果你用過(guò)其它語(yǔ)言的正則表達(dá)式,那么你一眼就能看出反斜杠的與眾不同。在其它語(yǔ)言里,""的意思是"我只是要在正則表達(dá)式里插入一個(gè)反斜杠。沒(méi)什么特別的意思。"但是在Java里,""的意思是"我要插入一個(gè)正則表達(dá)式的反斜杠,所以跟在它后面的那個(gè)字符的意思就變了。"舉例來(lái)說(shuō),如果你想表示一個(gè)或更多的"單詞字符",那么這個(gè)正則表達(dá)式就應(yīng)該是"w+"。如果你要插入一個(gè)反斜杠,那就得用""。不過(guò)像換行,跳格之類的還是只用一根反斜杠:"nt"。
這里只給你講一個(gè)例子;你應(yīng)該JDK文檔的java.util.regex.Pattern加到收藏夾里,這樣就能很容易地找到各種正則表達(dá)式的模式了。 邏輯運(yùn)算符
XY X 后面跟著 Y
X|Y X或Y
(X) 一個(gè)"要匹配的組(capturing group)". 以后可以用i來(lái)表示第i個(gè)被匹配的組。
邊界匹配符
^ 一行的開(kāi)始
$ 一行的結(jié)尾
b 一個(gè)單詞的邊界
B 一個(gè)非單詞的邊界
G 前一個(gè)匹配的結(jié)束
舉一個(gè)具體一些的例子。下面這些正則表達(dá)式都是合法的,而且都能匹配"Rudolph":
Rudolph
[rR]udolph
[rR][aeiou][a-z]ol.*
R.*數(shù)量表示符
"數(shù)量表示符(quantifier)"的作用是定義模式應(yīng)該匹配多少個(gè)字符。
Greedy(貪婪的): 除非另有表示,否則數(shù)量表示符都是greedy的。Greedy的表達(dá)式會(huì)一直匹配下去,直到匹配不下去為止。(如果你發(fā)現(xiàn)表達(dá)式匹配的結(jié)果與預(yù)期的不符),很有可能是因?yàn)?,你以為表達(dá)式會(huì)只匹配前面幾個(gè)字符,而實(shí)際上它是greedy的,因此會(huì)一直匹配下去。
Reluctant(勉強(qiáng)的): 用問(wèn)號(hào)表示,它會(huì)匹配最少的字符。也稱為lazy, minimal matching, non-greedy, 或ungreedy。
Possessive(占有的): 目前只有Java支持(其它語(yǔ)言都不支持)。它更加先進(jìn),所以你可能還不太會(huì)用。用正則表達(dá)式匹配字符串的時(shí)候會(huì)產(chǎn)生很多中間狀態(tài),(一般的匹配引擎會(huì)保存這種中間狀態(tài),)這樣匹配失敗的時(shí)候就能原路返回了。占有型的表達(dá)式不保存這種中間狀態(tài),因此也就不會(huì)回頭重來(lái)了。它能防止正則表達(dá)式的失控,同時(shí)也能提高運(yùn)行的效率。
Greedy Reluctant Possessive 匹配
X? X?? X?+ 匹配一個(gè)或零個(gè)X
X* X*? X*+ 匹配零或多個(gè)X
X+ X+? X++ 匹配一個(gè)或多個(gè)X
X{n} X{n}? X{n}+ 匹配正好n個(gè)X
X{n,} X{n,}? X{n,}+ 匹配至少n個(gè)X
X{n,m} X{n,m}? X{n,m}+ 匹配至少n個(gè),至多m個(gè)X
再提醒一下,要想讓表達(dá)式照你的意思去運(yùn)行,你應(yīng)該用括號(hào)把'X'括起來(lái)。比方說(shuō):
abc+似乎這個(gè)表達(dá)式能匹配一個(gè)或若干個(gè)'abc',但是如果你真的用它去匹配'abcabcabc'的話,實(shí)際上只會(huì)找到三個(gè)字符。因?yàn)檫@個(gè)表達(dá)式的意思是'ab'后邊跟著一個(gè)或多個(gè)'c'。要想匹配一個(gè)或多個(gè)完整的'abc',你應(yīng)該這樣:
(abc)+正則表達(dá)式能輕而易舉地把你給耍了;這是一種建立在Java之上的新語(yǔ)言。
CharSequence
JDK 1.4定義了一個(gè)新的接口,叫CharSequence。它提供了String和StringBuffer這兩個(gè)類的字符序列的抽象:
interface CharSequence {
charAt(int i);
length();
subSequence(int start, int end);
toString();
}為了實(shí)現(xiàn)這個(gè)新的CharSequence接口,String,StringBuffer以及CharBuffer都作了修改。很多正則表達(dá)式的操作都要拿CharSequence作參數(shù)。
Pattern和Matcher
先給一個(gè)例子。下面這段程序可以測(cè)試正則表達(dá)式是否匹配字符串。第一個(gè)參數(shù)是要匹配的字符串,后面是正則表達(dá)式。正則表達(dá)式可以有多個(gè)。在Unix/Linux環(huán)境下,命令行下的正則表達(dá)式還必須用引號(hào)。
當(dāng)你創(chuàng)建正則表達(dá)式時(shí),可以用這個(gè)程序來(lái)判斷它是不是會(huì)按照你的要求工作。 //: c12:TestRegularExpression.java
// Allows you to easly try out regular expressions.
// {Args: abcabcabcdefabc "abc+" "(abc)+" "(abc){2,}" }
import java.util.regex.*;
public class TestRegularExpression {
public static void main(String[] args) {
if(args.length < 2) {
System.out.println("Usage:n" +
"java TestRegularExpression " +
"characterSequence regularExpression+");
System.exit(0);
}
System.out.println("Input: "" + args[0] + """);
for(int i = 1; i < args.length; i++) {
System.out.println(
"Regular expression: "" + args[i] + """);
Pattern p = Pattern.compile(args[i]);
Matcher m = p.matcher(args[0]);
while(m.find()) {
System.out.println("Match "" + m.group() +
"" at positions " +
m.start() + "-" + (m.end() - 1));
}
}
}
} ///:~
Java的正則表達(dá)式是由java.util.regex的Pattern和Matcher類實(shí)現(xiàn)的。Pattern對(duì)象表示經(jīng)編譯的正則表達(dá)式。靜態(tài)的compile( )方法負(fù)責(zé)將表示正則表達(dá)式的字符串編譯成Pattern對(duì)象。正如上述例程所示的,只要給Pattern的matcher( )方法送一個(gè)字符串就能獲取一個(gè)Matcher對(duì)象。此外,Pattern還有一個(gè)能快速判斷能否在input里面找到regex的(注意,原文有誤,漏了方法名)
static boolean matches( regex, input)以及能返回String數(shù)組的split( )方法,它能用regex把字符串分割開(kāi)來(lái)。
只要給Pattern.matcher( )方法傳一個(gè)字符串就能獲得Matcher對(duì)象了。接下來(lái)就能用Matcher的方法來(lái)查詢匹配的結(jié)果了。
boolean matches()
boolean lookingAt()
boolean find()
boolean find(int start)matches( )的前提是Pattern匹配整個(gè)字符串,而lookingAt( )的意思是Pattern匹配字符串的開(kāi)頭。
find( )
Matcher.find( )的功能是發(fā)現(xiàn)CharSequence里的,與pattern相匹配的多個(gè)字符序列。例如: //: c12:FindDemo.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
import java.util.*;
public class FindDemo {
private static Test monitor = new Test();
public static void main(String[] args) {
Matcher m = Pattern.compile("w+")
.matcher("Evening is full of the linnet's wings");
while(m.find())
System.out.println(m.group());
int i = 0;
while(m.find(i)) {
System.out.print(m.group() + " ");
i++;
}
monitor.expect(new String[] {
"Evening",
"is",
"full",
"of",
"the",
"linnet",
"s",
"wings",
"Evening vening ening ning ing ng g is is s full " +
"full ull ll l of of f the the he e linnet linnet " +
"innet nnet net et t s s wings wings ings ngs gs s "
});
}
} ///:~
"w+"的意思是"一個(gè)或多個(gè)單詞字符",因此它會(huì)將字符串直接分解成單詞。find( )像一個(gè)迭代器,從頭到尾掃描一遍字符串。第二個(gè)find( )是帶int參數(shù)的,正如你所看到的,它會(huì)告訴方法從哪里開(kāi)始找——即從參數(shù)位置開(kāi)始查找。
Groups
Group是指里用括號(hào)括起來(lái)的,能被后面的表達(dá)式調(diào)用的正則表達(dá)式。Group 0 表示整個(gè)表達(dá)式,group 1表示第一個(gè)被括起來(lái)的group,以此類推。所以;
A(B(C))D里面有三個(gè)group:group 0是ABCD, group 1是BC,group 2是C。
你可以用下述Matcher方法來(lái)使用group:
public int groupCount( )返回matcher對(duì)象中的group的數(shù)目。不包括group0。
public String group( ) 返回上次匹配操作(比方說(shuō)find( ))的group 0(整個(gè)匹配)
public String group(int i)返回上次匹配操作的某個(gè)group。如果匹配成功,但是沒(méi)能找到group,則返回null。
public int start(int group)返回上次匹配所找到的,group的開(kāi)始位置。
public int end(int group)返回上次匹配所找到的,group的結(jié)束位置,最后一個(gè)字符的下標(biāo)加一。
下面我們舉一些group的例子: //: c12:Groups.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
public class Groups {
private static Test monitor = new Test();
static public final String poem =
"Twas brillig, and the slithy tovesn" +
"Did gyre and gimble in the wabe.n" +
"All mimsy were the borogoves,n" +
"And the mome raths outgrabe.nn" +
"Beware the Jabberwock, my son,n" +
"The jaws that bite, the claws that catch.n" +
"Beware the Jubjub bird, and shunn" +
"The frumious Bandersnatch.";
public static void main(String[] args) {
Matcher m =
Pattern.compile("(?m)(S+)s+((S+)s+(S+))$")
.matcher(poem);
while(m.find()) {
for(int j = 0; j <= m.groupCount(); j++)
System.out.print("[" + m.group(j) + "]");
System.out.println();
}
monitor.expect(new String[]{
"[the slithy toves]" +
"[the][slithy toves][slithy][toves]",
"[in the wabe.][in][the wabe.][the][wabe.]",
"[were the borogoves,]" +
"[were][the borogoves,][the][borogoves,]",
"[mome raths outgrabe.]" +
"[mome][raths outgrabe.][raths][outgrabe.]",
"[Jabberwock, my son,]" +
"[Jabberwock,][my son,][my][son,]",
"[claws that catch.]" +
"[claws][that catch.][that][catch.]",
"[bird, and shun][bird,][and shun][and][shun]",
"[The frumious Bandersnatch.][The]" +
"[frumious Bandersnatch.][frumious][Bandersnatch.]"
});
}
} ///:~
這首詩(shī)是Through the Looking Glass的,Lewis Carroll的"Jabberwocky"的第一部分??梢钥吹竭@個(gè)正則表達(dá)式里有很多用括號(hào)括起來(lái)的group,它是由任意多個(gè)連續(xù)的非空字符('S+')和任意多個(gè)連續(xù)的空格字符('s+')所組成的,其最終目的是要捕獲每行的最后三個(gè)單詞;'$'表示一行的結(jié)尾。但是'$'通常表示整個(gè)字符串的結(jié)尾,所以這里要明確地告訴正則表達(dá)式注意換行符。這一點(diǎn)是由'(?m)'標(biāo)志完成的(模式標(biāo)志會(huì)過(guò)一會(huì)講解)。
start( )和end( )
如果匹配成功,start( )會(huì)返回此次匹配的開(kāi)始位置,end( )會(huì)返回此次匹配的結(jié)束位置,即最后一個(gè)字符的下標(biāo)加一。如果之前的匹配不成功(或者沒(méi)匹配),那么無(wú)論是調(diào)用start( )還是end( ),都會(huì)引發(fā)一個(gè)IllegalStateException。下面這段程序還演示了matches( )和lookingAt( ): //: c12:StartEnd.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
public class StartEnd {
private static Test monitor = new Test();
public static void main(String[] args) {
String[] input = new String[] {
"Java has regular expressions in 1.4",
"regular expressions now expressing in Java",
"Java represses oracular expressions"
};
Pattern
p1 = Pattern.compile("rew*"),
p2 = Pattern.compile("Java.*");
for(int i = 0; i < input.length; i++) {
System.out.println("input " + i + ": " + input[i]);
Matcher
m1 = p1.matcher(input[i]),
m2 = p2.matcher(input[i]);
while(m1.find())
System.out.println("m1.find() '" + m1.group() +
"' start = "+ m1.start() + " end = " + m1.end());
while(m2.find())
System.out.println("m2.find() '" + m2.group() +
"' start = "+ m2.start() + " end = " + m2.end());
if(m1.lookingAt()) // No reset() necessary
System.out.println("m1.lookingAt() start = "
+ m1.start() + " end = " + m1.end());
if(m2.lookingAt())
System.out.println("m2.lookingAt() start = "
+ m2.start() + " end = " + m2.end());
if(m1.matches()) // No reset() necessary
System.out.println("m1.matches() start = "
+ m1.start() + " end = " + m1.end());
if(m2.matches())
System.out.println("m2.matches() start = "
+ m2.start() + " end = " + m2.end());
}
monitor.expect(new String[] {
"input 0: Java has regular expressions in 1.4",
"m1.find() 'regular' start = 9 end = 16",
"m1.find() 'ressions' start = 20 end = 28",
"m2.find() 'Java has regular expressions in 1.4'" +
" start = 0 end = 35",
"m2.lookingAt() start = 0 end = 35",
"m2.matches() start = 0 end = 35",
"input 1: regular expressions now " +
"expressing in Java",
"m1.find() 'regular' start = 0 end = 7",
"m1.find() 'ressions' start = 11 end = 19",
"m1.find() 'ressing' start = 27 end = 34",
"m2.find() 'Java' start = 38 end = 42",
"m1.lookingAt() start = 0 end = 7",
"input 2: Java represses oracular expressions",
"m1.find() 'represses' start = 5 end = 14",
"m1.find() 'ressions' start = 27 end = 35",
"m2.find() 'Java represses oracular expressions' " +
"start = 0 end = 35",
"m2.lookingAt() start = 0 end = 35",
"m2.matches() start = 0 end = 35"
});
}
} ///:~
注意,只要字符串里有這個(gè)模式,find( )就能把它給找出來(lái),但是lookingAt( )和matches( ),只有在字符串與正則表達(dá)式一開(kāi)始就相匹配的情況下才能返回true。matches( )成功的前提是正則表達(dá)式與字符串完全匹配,而lookingAt( )[67]成功的前提是,字符串的開(kāi)始部分與正則表達(dá)式相匹配。
匹配的模式(Pattern flags)
compile( )方法還有一個(gè)版本,它需要一個(gè)控制正則表達(dá)式的匹配行為的參數(shù):
Pattern Pattern.compile(String regex, int flag)flag的取值范圍如下: 編譯標(biāo)志 效果
Pattern.CANON_EQ 當(dāng)且僅當(dāng)兩個(gè)字符的"正規(guī)分解(canonical decomposition)"都完全相同的情況下,才認(rèn)定匹配。比如用了這個(gè)標(biāo)志之后,表達(dá)式"au030A"會(huì)匹配"?"。默認(rèn)情況下,不考慮"規(guī)范相等性(canonical equivalence)"。
Pattern.CASE_INSENSITIVE
(?i) 默認(rèn)情況下,大小寫(xiě)不明感的匹配只適用于US-ASCII字符集。這個(gè)標(biāo)志能讓表達(dá)式忽略大小寫(xiě)進(jìn)行匹配。要想對(duì)Unicode字符進(jìn)行大小不明感的匹配,只要將UNICODE_CASE與這個(gè)標(biāo)志合起來(lái)就行了。
Pattern.COMMENTS
(?x) 在這種模式下,匹配時(shí)會(huì)忽略(正則表達(dá)式里的)空格字符(譯者注:不是指表達(dá)式里的"s",而是指表達(dá)式里的空格,tab,回車之類)。注釋從#開(kāi)始,一直到這行結(jié)束。可以通過(guò)嵌入式的標(biāo)志來(lái)啟用Unix行模式。
Pattern.DOTALL
(?s) 在這種模式下,表達(dá)式'.'可以匹配任意字符,包括表示一行的結(jié)束符。默認(rèn)情況下,表達(dá)式'.'不匹配行的結(jié)束符。
Pattern.MULTILINE
(?m) 在這種模式下,'^'和'$'分別匹配一行的開(kāi)始和結(jié)束。此外,'^'仍然匹配字符串的開(kāi)始,'$'也匹配字符串的結(jié)束。默認(rèn)情況下,這兩個(gè)表達(dá)式僅僅匹配字符串的開(kāi)始和結(jié)束。
Pattern.UNICODE_CASE
(?u) 在這個(gè)模式下,如果你還啟用了CASE_INSENSITIVE標(biāo)志,那么它會(huì)對(duì)Unicode字符進(jìn)行大小寫(xiě)不明感的匹配。默認(rèn)情況下,大小寫(xiě)不明感的匹配只適用于US-ASCII字符集。
Pattern.UNIX_LINES
(?d) 在這個(gè)模式下,只有'n'才被認(rèn)作一行的中止,并且與'.','^',以及'$'進(jìn)行匹配。
在這些標(biāo)志里面,Pattern.CASE_INSENSITIVE,Pattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS還能幫我們把思路理清楚,并且/或者做文檔)。注意,你可以用在表達(dá)式里插記號(hào)的方式來(lái)啟用絕大多數(shù)的模式。這些記號(hào)就在上面那張表的各個(gè)標(biāo)志的下面。你希望模式從哪里開(kāi)始啟動(dòng),就在哪里插記號(hào)。
可以用"OR" ('|')運(yùn)算符把這些標(biāo)志合使用: //: c12:ReFlags.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
public class ReFlags {
private static Test monitor = new Test();
public static void main(String[] args) {
Pattern p = Pattern.compile("^java",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
Matcher m = p.matcher(
"java has regexnJava has regexn" +
"JAVA has pretty good regular expressionsn" +
"Regular expressions are in Java");
while(m.find())
System.out.println(m.group());
monitor.expect(new String[] {
"java",
"Java",
"JAVA"
});
}
} ///:~
這樣創(chuàng)建出來(lái)的正則表達(dá)式就能匹配以"java","Java","JAVA"...開(kāi)頭的字符串了。此外,如果字符串分好幾行,那它還會(huì)對(duì)每一行做匹配(匹配始于字符序列的開(kāi)始,終于字符序列當(dāng)中的行結(jié)束符)。注意,group( )方法僅返回匹配的部分。
split( )
所謂分割是指將以正則表達(dá)式為界,將字符串分割成String數(shù)組。
String[] split(CharSequence charseq)
String[] split(CharSequence charseq, int limit)這是一種既快又方便地將文本根據(jù)一些常見(jiàn)的邊界標(biāo)志分割開(kāi)來(lái)的方法。 //: c12:SplitDemo.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
import java.util.*;
public class SplitDemo {
private static Test monitor = new Test();
public static void main(String[] args) {
String input =
"This!!unusual use!!of exclamation!!points";
System.out.println(Arrays.asList(
Pattern.compile("!!").split(input)));
// Only do the first three:
System.out.println(Arrays.asList(
Pattern.compile("!!").split(input, 3)));
System.out.println(Arrays.asList(
"Aha! String has a split() built in!".split(" ")));
monitor.expect(new String[] {
"[This, unusual use, of exclamation, points]",
"[This, unusual use, of exclamation!!points]",
"[Aha!, String, has, a, split(), built, in!]"
});
}
} ///:~
第二個(gè)split( )會(huì)限定分割的次數(shù)。
正則表達(dá)式是如此重要,以至于有些功能被加進(jìn)了String類,其中包括split( )(已經(jīng)看到了),matches( ),replaceFirst( )以及replaceAll( )。這些方法的功能同Pattern和Matcher的相同。
替換操作
正則表達(dá)式在替換文本方面特別在行。下面就是一些方法:
replaceFirst(String replacement)將字符串里,第一個(gè)與模式相匹配的子串替換成replacement。
replaceAll(String replacement),將輸入字符串里所有與模式相匹配的子串全部替換成replacement。
appendReplacement(StringBuffer sbuf, String replacement)對(duì)sbuf進(jìn)行逐次替換,而不是像replaceFirst( )或replaceAll( )那樣,只替換第一個(gè)或全部子串。這是個(gè)非常重要的方法,因?yàn)樗梢哉{(diào)用方法來(lái)生成replacement(replaceFirst( )和replaceAll( )只允許用固定的字符串來(lái)充當(dāng)replacement)。有了這個(gè)方法,你就可以編程區(qū)分group,從而實(shí)現(xiàn)更強(qiáng)大的替換功能。
調(diào)用完appendReplacement( )之后,為了把剩余的字符串拷貝回去,必須調(diào)用appendTail(StringBuffer sbuf, String replacement)。
下面我們來(lái)演示一下怎樣使用這些替換方法。說(shuō)明一下,這段程序所處理的字符串是它自己開(kāi)頭部分的注釋,是用正則表達(dá)式提取出來(lái)并加以處理之后再傳給替換方法的。 //: c12:TheReplacements.java
import java.util.regex.*;
import java.io.*;
import com.bruceeckel.util.*;
import com.bruceeckel.simpletest.*;
/*! Here's a block of text to use as input to
the regular expression matcher. Note that we'll
first extract the block of text by looking for
the special delimiters, then process the
extracted block. !*/
public class TheReplacements {
private static Test monitor = new Test();
public static void main(String[] args) throws Exception {
String s = TextFile.read("TheReplacements.java");
// Match the specially-commented block of text above:
Matcher mInput =
Pattern.compile("/*!(.*)!*/", Pattern.DOTALL)
.matcher(s);
if(mInput.find())
s = mInput.group(1); // Captured by parentheses
// Replace two or more spaces with a single space:
s = s.replaceAll(" {2,}", " ");
// Replace one or more spaces at the beginning of each
// line with no spaces. Must enable MULTILINE mode:
s = s.replaceAll("(?m)^ +", "");
System.out.println(s);
s = s.replaceFirst("[aeiou]", "(VOWEL1)");
StringBuffer sbuf = new StringBuffer();
Pattern p = Pattern.compile("[aeiou]");
Matcher m = p.matcher(s);
// Process the find information as you
// perform the replacements:
while(m.find())
m.appendReplacement(sbuf, m.group().toUpperCase());
// Put in the remainder of the text:
m.appendTail(sbuf);
System.out.println(sbuf);
monitor.expect(new String[]{
"Here's a block of text to use as input to",
"the regular expression matcher. Note that we'll",
"first extract the block of text by looking for",
"the special delimiters, then process the",
"extracted block. ",
"H(VOWEL1)rE's A blOck Of tExt tO UsE As InpUt tO",
"thE rEgUlAr ExprEssIOn mAtchEr. NOtE thAt wE'll",
"fIrst ExtrAct thE blOck Of tExt by lOOkIng fOr",
"thE spEcIAl dElImItErs, thEn prOcEss thE",
"ExtrActEd blOck. "
});
}
} ///:~
我們用前面介紹的TextFile.read( )方法來(lái)打開(kāi)和讀取文件。mInput的功能是匹配'/*!' 和 '!*/' 之間的文本(注意一下分組用的括號(hào))。接下來(lái),我們將所有兩個(gè)以上的連續(xù)空格全都替換成一個(gè),并且將各行開(kāi)頭的空格全都去掉(為了讓這個(gè)正則表達(dá)式能對(duì)所有的行,而不僅僅是第一行起作用,必須啟用多行模式)。這兩個(gè)操作都用了String的replaceAll( )(這里用它更方便)。注意,由于每個(gè)替換只做一次,因此除了預(yù)編譯Pattern之外,程序沒(méi)有額外的開(kāi)銷。
replaceFirst( )只替換第一個(gè)子串。此外,replaceFirst( )和replaceAll( )只能用常量(literal)來(lái)替換,所以如果你每次替換的時(shí)候還要進(jìn)行一些操作的話,它們是無(wú)能為力的。碰到這種情況,你得用appendReplacement( ),它能讓你在進(jìn)行替換的時(shí)候想寫(xiě)多少代碼就寫(xiě)多少。在上面那段程序里,創(chuàng)建sbuf的過(guò)程就是選group做處理,也就是用正則表達(dá)式把元音字母找出來(lái),然后換成大寫(xiě)的過(guò)程。通常你得在完成全部的替換之后才調(diào)用appendTail( ),但是如果要模仿replaceFirst( )(或"replace n")的效果,你也可以只替換一次就調(diào)用appendTail( )。它會(huì)把剩下的東西全都放進(jìn)sbuf。
你還可以在appendReplacement( )的replacement參數(shù)里用"$g"引用已捕獲的group,其中'g' 表示group的號(hào)碼。不過(guò)這是為一些比較簡(jiǎn)單的操作準(zhǔn)備的,因而其效果無(wú)法與上述程序相比。
reset( )
此外,還可以用reset( )方法給現(xiàn)有的Matcher對(duì)象配上個(gè)新的CharSequence。 //: c12:Resetting.java
import java.util.regex.*;
import java.io.*;
import com.bruceeckel.simpletest.*;
public class Resetting {
private static Test monitor = new Test();
public static void main(String[] args) throws Exception {
Matcher m = Pattern.compile("[frb][aiu][gx]")
.matcher("fix the rug with bags");
while(m.find())
System.out.println(m.group());
m.reset("fix the rig with rags");
while(m.find())
System.out.println(m.group());
monitor.expect(new String[]{
"fix",
"rug",
"bag",
"fix",
"rig",
"rag"
});
}
} ///:~
如果不給參數(shù),reset( )會(huì)把Matcher設(shè)到當(dāng)前字符串的開(kāi)始處。
正則表達(dá)式與Java I/O
到目前為止,你看到的都是用正則表達(dá)式處理靜態(tài)字符串的例子。下面我們來(lái)演示一下怎樣用正則表達(dá)式掃描文件并且找出匹配的字符串。受Unix的grep啟發(fā),我寫(xiě)了個(gè)JGrep.java,它需要兩個(gè)參數(shù):文件名,以及匹配字符串用的正則表達(dá)式。它會(huì)把匹配這個(gè)正則表達(dá)式那部分內(nèi)容及其所屬行的行號(hào)打印出來(lái)。 //: c12:JGrep.java
// A very simple version of the "grep" program.
// {Args: JGrep.java "b[Ssct]w+"}
import java.io.*;
import java.util.regex.*;
import java.util.*;
import com.bruceeckel.util.*;
public class JGrep {
public static void main(String[] args) throws Exception {
if(args.length < 2) {
System.out.println("Usage: java JGrep file regex");
System.exit(0);
}
Pattern p = Pattern.compile(args[1]);
// Iterate through the lines of the input file:
ListIterator it = new TextFile(args[0]).listIterator();
while(it.hasNext()) {
Matcher m = p.matcher((String)it.next());
while(m.find())
System.out.println(it.nextIndex() + ": " +
m.group() + ": " + m.start());
}
}
} ///:~
文件是用TextFile打開(kāi)的(本章的前半部分講的)。由于TextFile會(huì)把文件的各行放在ArrayList里面,而我們又提取了一個(gè)ListIterator,因此我們可以在文件的各行當(dāng)中自由移動(dòng)(既能向前也可以向后)。
每行都會(huì)有一個(gè)Matcher,然后用find( )掃描。注意,我們用ListIterator.nextIndex( )跟蹤行號(hào)。
測(cè)試參數(shù)是JGrep.java和以[Ssct]開(kāi)頭的單詞。
還需要StringTokenizer嗎?
看到正則表達(dá)式能提供這么強(qiáng)大的功能,你可能會(huì)懷疑,是不是還需要原先的StringTokenizer。JDK 1.4以前,要想分割字符串,只有用StringTokenizer。但現(xiàn)在,有了正則表達(dá)式之后,它就能做得更干凈利索了。 //: c12:ReplacingStringTokenizer.java
import java.util.regex.*;
import com.bruceeckel.simpletest.*;
import java.util.*;
public class ReplacingStringTokenizer {
private static Test monitor = new Test();
public static void main(String[] args) {
String input = "But I'm not dead yet! I feel happy!";
StringTokenizer stoke = new StringTokenizer(input);
while(stoke.hasMoreElements())
System.out.println(stoke.nextToken());
System.out.println(Arrays.asList(input.split(" ")));
monitor.expect(new String[] {
"But",
"I'm",
"not",
"dead",
"yet!",
"I",
"feel",
"happy!",
"[But, I'm, not, dead, yet!, I, feel, happy!]"
});
}
} ///:~
有了正則表達(dá)式,你就能用更復(fù)雜的模式將字符串分割開(kāi)來(lái)——要是交給StringTokenizer的話,事情會(huì)麻煩得多。我可以很有把握地說(shuō),正則表達(dá)式可以取代StringTokenizer。
“java正則表達(dá)式的實(shí)例用法”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
本文名稱:java正則表達(dá)式的實(shí)例用法
網(wǎng)站路徑:http://muchs.cn/article14/gjssde.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營(yíng)銷型網(wǎng)站建設(shè)、App設(shè)計(jì)、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站維護(hù)、定制網(wǎng)站、微信公眾號(hào)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)