天天看點

JAVA正規表達式--java.util.regex--Pattern和Matcher

http://www.sunjsp.com JAVA正規表達式--Pattern和Matcher

現在JDK1.4裡終于有了自己的正規表達式API包,JAVA程式員可以免去找第三方提供的正規表達式庫的周折了,我們現在就馬上來了解一下這個SUN提供的-遲來恩物-

-對我來說确實如此。

1.簡介:

java.util.regex是一個用正規表達式所訂制的模式來對字元串進行比對工作的類庫包。

它包括兩個類:Pattern和Matcher Pattern

一個Pattern是一個正規表達式經編譯後的表現模式。

Matcher

一個Matcher對象是一個狀态機器,它依據Pattern對象做為比對模式對字元串展開比對檢查。

首先一個Pattern執行個體訂制了一個所用文法與PERL的類似的正規表達式經編譯後的模式,然後一個Matcher執行個體在這個給定的Pattern執行個體的模式-控制下進行字元串的比對工作。

以下我們就分别來看看這兩個類:

2.Pattern類:

Pattern的方法如下:

static Pattern compile(String regex) 将給定的正規表達式編譯并賦予給Pattern類

static Pattern compile(String regex, int flags) 同上,但增加flag參數的指定,可選的flag參數包括:CASE

INSENSITIVE,MULTILINE,DOTALL,UNICODE CASE, CANON EQ

int flags() 傳回目前Pattern的比對flag參數.

Matcher matcher(CharSequence input) 生成一個給定命名的Matcher對象

static boolean matches(String regex, CharSequence input) 編譯給定的正規表達式并且對輸入的字串以該正規表達式為模開展比對,該方法适合于該正規表達式隻會使用一次的情況,也就是隻進行一次比對工作,因為這種情況下并-不需要生成一個Matcher執行個體。

String pattern() 傳回該Patter對象所編譯的正規表達式。

String[] split(CharSequence input) 将目标字元串按照Pattern裡所包含的正規表達式為模進行分割。

String[] split(CharSequence input, int limit) 作用同上,增加參數limit目的在于要指定分割的段數,如将limi設為2,那麼目标字元串将根據正規表達式分為割為兩段。

一個正規表達式,也就是一串有特定意義的字元,必須首先要編譯成為一個Pattern類的執行個體,這個Pattern對象将會使用matcher()方法來生成一-個Matcher執行個體,接着便可以使用該Matcher執行個體以編譯的正規表達式為基礎對目标字元串進行比對工作,多個Matcher是可以共用一個Pattern對象的。

現在我們先來看一個簡單的例子,再通過分析它來了解怎樣生成一個Pattern對象并且編譯一個正規表達式,最後根據這個正規表達式将目标字元串進行分割:

import java.util.regex.*;

public class Replacement{

public static void main(String[] args) throws Exception {

    // 生成一個Pattern,同時編譯一個正規表達式

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

    //用Pattern的split()方法把字元串按"/"分割

    String[] result = p.split(

    "Kevin has seen《LEON》seveal times,because it is a good film."

    +"/凱文已經看過《這個殺手不太冷》幾次了,因為它是一部"

    +"好電影。/名詞:凱文。");

    for (int i=0; i<result.length; i++)

        System.out.println(result[i]);

    }

}

輸出結果為:

Kevin has seen《LEON》seveal times,because it is a good film.

凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。

名詞:凱文。

很明顯,該程式将字元串按"/"進行了分段,我們以下再使用

split(CharSequence input, int limit)方法來指定分段的段數,程式改動為:

tring[] result = p.split("Kevin has seen《LEON》seveal times,because

it is a good film./凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。",2);

這裡面的參數"2"表明将目智語句分為兩段。

輸出結果則為:

Kevin has seen《LEON》seveal times,because it is a good film.

凱文已經看過《這個殺手不太冷》幾次了,因為它是一部好電影。/名詞:凱文。

由上面的例子,我們可以比較出java.util.regex包在構造Pattern對象以及編譯指定的正規表達式的實作手法與我們在上一篇中所介紹的Jaka-rta-ORO

包在完成同樣工作時的差别,Jakarta-ORO

包要先構造一個PatternCompiler類對象接着生成一個Pattern對象,再将正規表達式用該PatternCompiler類的compile(-)方法來将所需的正規表達式編譯賦予Pattern類:

PatternCompiler orocom=new Perl5Compiler();

Pattern pattern=orocom.compile("REGULAR EXPRESSIONS");

PatternMatcher matcher=new Perl5Matcher();

但是在java.util.regex包裡,我們僅需生成一個Pattern類,直接使用它的compile()方法就可以達到同樣的效果:

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

是以似乎java.util.regex的構造法比Jakarta-ORO更為簡潔并容易了解。

3.Matcher類:

Matcher方法如下:

Matcher appendReplacement(StringBuffer sb,String replacement) 将目前比對子串替換為指定字元串,并且将替換後的子串以及其之前到上次比對子串之後的字元串段添加到一個StringBuffer對象裡。

StringBuffer appendTail(StringBuffer sb) 将最後一次比對工作後剩餘的字元串添加到一個StringBuffer對象裡。類包裡的解釋是:實作非終端追加和替換步驟。

int end() 傳回目前比對的子串的最後一個字元在原目标字元串中的索引位置。

int end(int group) 傳回與比對模式裡指定的組相比對的子串最後一個字元的位置。

boolean find() 嘗試在目标字元串裡查找下一個比對子串。

boolean find(int start) 重設Matcher對象,并且嘗試在目标字元串裡從指定的位置開始查找下一個比對的子串。

String group() 傳回目前查找而獲得的與組比對的所有子串内容

String group(int group) 傳回目前查找而獲得的與指定的組比對的子串内容

int groupCount() 傳回目前查找所獲得的比對組的數量。

boolean lookingAt() 檢測目标字元串是否以比對的子串起始。

boolean matches() 嘗試對整個目标字元展開比對檢測,也就是隻有整個目标字元串完全比對時才傳回真值。

Pattern pattern() 傳回該Matcher對象的現有比對模式,也就是對應的Pattern對象。

String replaceAll(String replacement) 将目标字元串裡與既有模式相比對的子串全部替換為指定的字元串。

String replaceFirst(String replacement) 将目标字元串裡第一個與既有模式相比對的子串替換為指定的字元串。

Matcher reset() 重設該Matcher對象。

Matcher reset(CharSequence input) 重設該Matcher對象并且指定一個新的目标字元串。

int start() 傳回目前查找所獲子串的開始字元在原目标字元串中的位置。

int start(int group) 傳回目前查找所獲得的和指定組比對的子串的第一個字元在原目标字元串中的位置。

(光看方法的解釋是不是很不好了解?不要急,待會結合例子就比較容易明白了)

一個Matcher執行個體是被用來對目标字元串進行基于既有模式(也就是一個給定的Pattern所編譯的正規表達式)進行比對查找的,所有往Matcher的輸-入都是通過CharSequence接口提供的,這樣做的目的在于可以支援對從多元化的資料源所提供的資料進行比對工作。

我們分别來看看各方法的使用:

★matches()/lookingAt ()/find():

一個Matcher對象是由一個Pattern對象調用其matcher()方法而生成的,一旦該Matcher對象生成,它就可以進行三種不同的比對查找操作-:

matches()方法嘗試對整個目标字元展開比對檢測,也就是隻有整個目标字元串完全比對時才傳回真值。

lookingAt()方法将檢測目标字元串是否以比對的子串起始。

find()方法嘗試在目标字元串裡查找下一個比對子串。

以上三個方法都将傳回一個布爾值來表明成功與否。

★replaceAll ()/appendReplacement()/appendTail():

Matcher類同時提供了四個将比對子串替換成指定字元串的方法:

replaceAll()

replaceFirst()

appendReplacement()

appendTail()

replaceAll()與replaceFirst()的用法都比較簡單,請看上面方法的解釋。我們主要重點了解一下appendReplacement()-和appendTail()方法。

appendReplacement(StringBuffer sb, String replacement) 将目前比對子串替換為指定字元串,并且将替換後的子串以及其之前到上次比對子串之後的字元串段添加到一個StringBuffer對象裡,而

appendTail(StringBuffer sb) 方法則将最後一次比對工作後剩餘的字元串添加到一個StringBuffer對象裡。

例如,有字元串fatcatfatcatfat,

假設既有正規表達式模式為"cat",第一次比對後調用appendReplacement(sb,"dog"-),那麼這時StringBuffer sb 的内容為fatdog,也就是fatcat中的cat被替換為dog并且與比對子串前的内容加到sb裡,而第二次比對後調用 appendReplaceme-nt(sb,"dog"),那麼sb的内容就變為fatdogfatdog,如果最後再調用一次appendTail (sb),那麼sb最終的内容将是fatdogfatdogfat。

還是有點模糊?那麼我們來看個簡單的程式:

//該例将把句子裡的"Kelvin"改為"Kevin"

import java.util.regex.*;

public class MatcherTest{

public static void main(String[] args)

throws Exception {

    //生成Pattern對象并且編譯一個簡單的正規表達式"Kelvin"

    Pattern p = Pattern.compile("Kevin");

    //用Pattern類的matcher()方法生成一個Matcher對象

    Matcher m = p.matcher("Kelvin Li and Kelvin Chan are both working in Kelvin Chen's KelvinSoftShop company");

    StringBuffer sb = new StringBuffer();

    int i=0;

    //使用find()方法查找第一個比對的對象

    boolean result = m.find();

    //使用循環将句子裡所有的kelvin找出并替換再将内容加到sb裡

    while(result) {

      i++;

      m.appendReplacement(sb, "Kevin");

      System.out.println("第"+i+"次比對後sb的内容是:"+sb);

      //繼續查找下一個比對對象

      result = m.find();

    }

    //最後調用appendTail()方法将最後一次比對後的剩餘字元串加到sb裡;

    m.appendTail(sb);

    System.out.println("調用m.appendTail(sb)後sb的最終内容是:"+

    sb.toString());

}

}

最終輸出結果為:

第1次比對後sb的内容是:Kevin

第2次比對後sb的内容是:Kevin Li and Kevin

第3次比對後sb的内容是:Kevin Li and Kevin Chan are both working in Kevin

第4次比對後sb的内容是:Kevin Li and Kevin Chan are both working in Kevin Chen's Kevin

調用m.appendTail(sb)後sb的最終内容是:Kevin Li and Kevin Chan are both working in Kevin Chen's KevinSoftShop company.

看了上面這個例程是否對appendReplacement(),appendTail()兩個方法的使用更清楚呢,如果還是不太肯定最好自己動手寫幾行代碼測-試一下。

★group()/group(int group)/groupCount():

該系列方法與我們在上篇介紹的Jakarta-ORO中的MatchResult

.group()方法類似(有關Jakarta-ORO請參考上篇的内容),都是要傳回與組比對的子串内容,下面代碼将很好解釋其用法:

import java.util.regex.*;

public class GroupTest{

public static void main(String[] args)

throws Exception {

    Pattern p = Pattern.compile("(ca)(t)");

    Matcher m = p.matcher("one cat,two cats in the yard");

    StringBuffer sb = new StringBuffer();

    boolean result = m.find();

    System.out.println("該次查找獲得比對組的數量為:"+m.groupCount());

    for(int i=1;i<=m.groupCount();i++){

       System.out.println(" 第"+i+"組的子串内容為:"+m.group(i));

    }

}

}

輸出為:

該次查找獲得比對組的數量為:2

第1組的子串内容為:ca

第2組的子串内容為:t

Matcher對象的其他方法因比較好了解且由于篇幅有限,請讀者自己程式設計驗證。

4.一個檢驗Email位址的小程式:

最後我們來看一個檢驗Email位址的例程,該程式是用來檢驗一個輸入的EMAIL位址裡所包含的字元是否合法,雖然這不是一個完整的EMAIL位址檢驗程式,-它不能檢驗所有可能出現的情況,但在必要時您可以在其基礎上增加所需功能。

import java.util.regex.*;

public class Email {

public static void main(String[] args) throws Exception {

String input = args[0];

//檢測輸入的EMAIL位址是否以

非法符号"."或"@"作為起始字元

Pattern p = Pattern.compile("^/.|^/@");

Matcher m = p.matcher(input);

if (m

//檢測是否以"www."為起始

p = Pattern.compile("^www/.");

m = p.matcher(input);

if (m

//檢測是否包含非法字元

p = Pattern.compile("[^A-Za-z0-9/./@_/-~#]+");

m = p.matcher(input);

StringBuffer sb = new StringBuffer();

boolean result = m.find();

boolean deletedIllegalChars = false;

while(result) {

//如果找到了非法字元那麼就設下标記

deletedIllegalChars = true;

//如果裡面包含非法字元如冒号雙引号等,那麼就把他們消去,加到SB裡面

m.appendReplacement(sb, "");

result = m.find();

}

m.appendTail(sb);

input = sb.toString();

if (deletedIllegalChars) {

System.out.println("輸入的EMAIL位址裡包含有冒号、逗号等非法字元,請修改");

System.out.println("您現在的輸入為: "+args[0]);

System.out.println("修改後合法的位址應類似: "+input);

}

}

}

例如,我們在指令行輸入:java Email [email protected]

那麼輸出結果将會是:EMAIL位址不能以'www.'起始

如果輸入的EMAIL為@[email protected]

則輸出為:EMAIL位址不能以'.'或'@'作為起始字元

當輸入為:[email protected]

那麼輸出就是:

輸入的EMAIL位址裡包含有冒号、逗号等非法字元,請修改

您現在的輸入為: [email protected]

修改後合法的位址應類似: [email protected]

5.總結:

本文介紹了jdk1.4.0-beta3裡正規表達式庫--java.util.regex中的類以及其方法,如果結合與上一篇中所介紹的Jakarta-OR-O

API作比較,讀者會更容易掌握該API的使用,當然該庫的性能将在未來的日子裡不斷擴充,希望獲得最新資訊的讀者最好到及時到SUN的網站去了解。

6.結束語:

本來計劃再多寫一篇介紹一下需付費的正規表達式庫中較具代表性的作品,但覺得既然有了免費且優秀的正規表達式庫可以使用,何必還要去找需付費的呢,相信很多讀者-也是這麼想的:,是以有興趣了解更多其他的第三方正規表達式庫的朋友可以自己到網上查找或者到我在參考資料裡提供的網址去看看。

參考資料

java.util.regex的幫助文檔

Dana Nourie 和Mike McCloskey所寫的Regular Expressions and the

Java? Programming Language

需要更多的第三方正規表達式資源以及基于它們所開發的應用程式請看http://www.meurrens.org/ip-Links/java/regex/index.html

關于作者

陳廣佳 Kevin

Chen,汕頭大學電子資訊工程系工科學士,台灣大新出版社珠海區開發部,現正圍繞中日韓電子資料使用JAVA開發電子詞典等相關項目。可通過E-mail:[email protected]于他聯系。