在Sun的Java JDK 1.40版本中,Java內建了支援Regex的包,本文就拋磚引玉地介紹了如何使用java.util.regex包。
可粗數量級估計一下,除了偶爾用Linux的外,其他Linu x使用者都會遇到Regex。Regex是個極端強大工具,而且在字串模式-匹配和字串模式-替換方面富有彈性。在Unix世界裡,Regex幾乎沒有什麼限制,可肯定的是,它應用非常之廣泛。
Regex的引擎已被許多普通的Unix工具所實現,包括grep,awk,vi和Emacs等。此外,許多使用比較廣泛的指令碼語言也支援Regex,比如Python,Tcl,JavaScript,以及最著名的Perl。
我很早以前就是個Perl方面的駭客,如果你和我一樣話,你也會非常依賴你手邊的這些強大的text-munging工具。近幾年來,像其他程式開發人員一樣,我也越來越關注Java的開發。
Java作為一種開發語言,有許多值得推薦的地方,但是它一直以來沒有內建對Regex的支援。直到最近,藉助於第三方的類庫,Java開始支援Regex,但這些第三方的類庫都不一致、相容性差,而且維護代碼起來很糟糕。這個缺點,對我選擇Java作為首要的開發工具來說,一直是個巨大的顧慮之處。
你可以想象,當我知道Sun的Java JDK 1.40版本包含了java.util.regex(一個完全開放、內建的Regex包)時,是多麼的高興!很搞笑的說,我花好些時間去挖掘這個被隱藏起來的寶石。我非常驚奇的是,Java這樣的一個很大改進(內建了java.util.regex包)為什麼不多公開一點呢?!
最近,Java雙腳都跳進了Regex的世界。java.util.regex包在支援正則表達也有它的過人之處,另外Java也提供詳細的相關說明文檔。使得朦朦朧朧的regex神秘景象也慢慢被撥開。有一些Regex的構成(可能最顯著的是,在於糅合了字元類庫)在Perl都找不到。
在regex包中,包括了兩個類,Pattern(模式類)和Matcher(匹配器類)。Pattern類是用來表達和陳述所要搜尋模式的對象,Matcher類是真正影響搜尋的對象。另加一個新的例外類,PatternSyntaxException,當遇到不合法的搜尋模式時,會拋出例外。
即使對Regex很熟悉,你會發現,通過java使用Regex也相當簡單。要說明的一點是,對那些被Perl的單行匹配所寵壞的Perl狂熱愛好者來說,在使用java的regex包進行替換操作時,會比他們所以前常用的方法費事些。
本文的局限之處,它不是一篇Regex用法的完全教程。如果讀者要對正則表達進一步瞭解的話,推薦閱讀Jeffrey Frieldl的Mastering Regular Expressions,該書由O’Reilly出版社出版。我下面就舉一些例子來教讀者如何使用Regex,以及如何更簡單地去使用它。
/////////////////////////////////////////////////////////////////////////////////////////
設計一個簡單的運算式來匹配任何電話號碼數字可能是比較複雜的事情,原因在於電話號碼格式有很多種情況。所有必須選擇一個比較有效模式。比如:(212) 555-1212, 212-555-1212和212 555 1212,某些人會認為它們都是等價的。
首先讓我們構成一個Regex。為簡單起見,先構成一個Regex來識別下面格式的電話號碼數字:(nnn)nnn-nnnn。
第一步,建立一個pattern對象來匹配上面的子字串。一旦程式運行後,如果需要的話,可以讓這個對象一般化。匹配上面格式的正則表達可以這樣構成:(/d{3})/s/d{3}-/d{4},其中/d單字元類型用來匹配從0到9的任何數字,另外{3}重複符號,是個簡便的記號,用來表示有3個連續的數字位,也等效於(/d/d/d)。/s也另外一個比較有用的單字元類型,用來匹配空格,比如Space鍵,tab鍵和分行符號。
是不是很簡單?但是,如果把這個Regex的模式用在java程式中,還要做兩件事。對java的解譯器來說,在反斜線字元(/)前的字元有特殊的含義。在java中,與regex有關的包,並不都能理解和識別反斜線字元(/),儘管可以試試看。但為避免這一點,即為了讓反斜線字元(/)在模式對象中被完全地傳遞,應該用雙反斜線字元(/)。此外圓括弧在正則表達中兩層含義,如果想讓它解釋為字面上意思(即圓括弧),也需要在它前面用雙反斜線字元(/)。也就是像下面的一樣:
//(//d{3}//)//s//d{3}-//d{4}
現在介紹怎樣在java代碼中實現剛才所講的Regex。要記住的事,在用Regex的包時,在你所定義的類前需要包含該包,也就是這樣的一行:
import java.util.regex.*;
下面的一段代碼實現的功能是,從一個文字檔逐行讀入,並逐行搜尋電話號碼數字,一旦找到所匹配的,然後輸出在控制台。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
BufferedReader in ; Pattern pattern = Pattern.compile( "//(//d{3}//)//s//d{3}-//d{4}" ); in |