Java正則表達式

正則表達式在處理文本方面用處非常大,最早像在Perl和awk語言中,提供了這種機制,Java在Java 2中也增加了正則表達式這個包java.util.regex。這個包爲用戶使用正則表達式,提供了易用而全面的支持。我的研究方向是web挖掘。從網頁中提取內容,處理文本,當然需要正則表達式這個強大的工具了。 
一、首先我們看一下怎麼使用正則表達式的一個例子: 
A Matcher examines the results of applying a pattern. 
我們希望從這句話中找到所有開頭爲a的單詞。 
當然這只是一個簡單的例子,你可以使用String提供的split方法,得到單詞數組,然後 
遍歷各個單詞看是否是否開頭爲a 
我們現在看看怎麼使用正則表達式來處理這個問題: 
Java代碼  收藏代碼
  1. import java.util.regex.*;  
  2.   
  3. public class FindA{  
  4.   public static void main(String args[])  
  5.   throws Exception{  
  6.   
  7.     String candidate =  
  8.      "A Matcher examines the results of applying a pattern.";  
  9.     String regex = "\\ba\\w*\\b";  
  10.     Pattern p = Pattern.compile(regex);  
  11.     Matcher m = p.matcher(candidate);  
  12.     String val = null;  
  13.     System.out.println("INPUT: " + candidate);  
  14.     System.out.println("REGEX: " + regex +"\r\n");  
  15.     while (m.find()){  
  16.       val = m.group();  
  17.       System.out.println("MATCH: " + val);  
  18.     }  
  19.     if (val == null) {  
  20.       System.out.println("NO MATCHES: ");  
  21.     }  
  22.   }  
  23. }  

從這個例子我們可以看到正則表達式涉及到的兩個類Matcher和Pattern,我們以後會專門討論着連個類。現在主要看看使用正則表達式的流程: 
首先使用 Pattern的一個靜態的方法compile來創建Pattern對象, 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile(regex);  

然後調用Pattern的方法matcher 
Java代碼  收藏代碼
  1. Matcher m = p.matcher(candidate);  

得到了Matcher對象,Matcher對象保存了許多匹配信息,然後可以通過find()方法 
查找匹配的部分,如果有匹配的部分,返回真,使用m.group方法得到匹配的各組值, 
否則find返回false. 
當然這只是一般的過程,還有許多更細的方法,在以後會陸續的總結,下面我們看一下 
Java代碼  收藏代碼
  1. String regex = "\\ba\\w*\\b";  

這個就是一個正則表達式,b,w,*都是正則表達式的meta character原字符, 
\b表示單詞的邊界,w表示任意的可構成單詞的字母數字,*表示前面的字母(當然可以 
是更復雜的組之類的了東東)重複0次或0次以上,a當然還是a了。所以這個regex就 
匹配單詞開頭爲a的單詞了。 
二、下面總結一下基本的正則表達式的meta character以及它們含義: 
.  匹配任意一個字符 $ 匹配一行的結尾 ^ 匹配一行的開頭(在[]裏面表示否定) 
{} 定義了一個範圍  [] 定義了一個字符類 () 定義了一個組 
*前面出現0次以上   + 前面匹配一次以上 ?前面出現0次或一次   
\ 後面的字符不會看作metacharacter  \w 字母數字下劃線 \W 非字母數字下劃線 
\d 單個數字 \D單個非數字 | 或,二者之一 &&與操作符 \b單詞邊界 
下面看看幾個簡單的例子: 
[abc] a、b 或 c(簡單類) 
[^abc] 任何字符,除了a、b 或 c(否定) 
[a-zA-Z] a 到 z 或 A 到 Z,兩頭的字母包括在內(範圍) 
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](並集) 
[a-z&&[def]] d、e 或 f(交集) 
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](減去) 
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](減去) 
三、java.util.regex提供的操作接口: 
java.util.regex包提供了操作正則表達式的模型,整個模型優雅而簡潔,只有三個類:Pattern、Matcher和 
PatternSyntaxException。下面將要總結他們提供的方法,以及如何靈活應用來處理文本。 

我們還是從Pattern的靜態工廠方法來擴展吧: 
Java代碼  收藏代碼
  1. static Pattern compile(String regex)   

將給定的正則表達式編譯到模式中,並創建Pattern對象,這個方法通常是操作正則表達式的第一步,從前面那個例子 
我們也可以看到整個的流程。 
在看看一個重載的compile方法: 
Java代碼  收藏代碼
  1.    
  2. static Pattern compile(String regex, int flags)   

將給定的正則表達式編譯到具有給定標誌的模式中。 這個方法參數flags提供了一些特殊的選項來用於特殊的處理, 
我們下面看看可使用的選項: 
UNIX_LINES:這個主要處理UNIX和其他的操作系統在行結束符不一樣的問題,UNIX使用\n代表一行的終止,而Windows 
則使用了\r\n,\n,\r,\u2028或者\u0085作爲一行的結束符。 
CASE_INSENSITIVE:當我們在匹配的時候要忽略字符大小寫時 
COMMENTS:允許我們在正則表達式中使用註釋,例如 
Java代碼  收藏代碼
  1. Pattern p =Pattern.compile("A    #matches uppercase US-ASCII char code 65",Pattern.COMMENTS);  

MULTILINE:表明要輸入多行,他們有自己的終止字符。 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile("^", Pattern.MULTILINE);  

如果你的輸入的字符串是:This is a sentence.\n So is this.. 
這樣我們匹配的字符時This中的T和So中的S,如果不使用MULTILINE,則只會匹配T 
DOTALL:使用這個選項之後metacharacter .就可以包括一行的終止字符了,如果沒有這個選項, 
一行的終止字符,並不會考慮在字符串之內的。 
使用這個選項會降低效率 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile(".", Pattern.DOTALL);  

如果我們輸入的是Test\n,則匹配的字符是5個。 
UNICODE_CASE:處理UNICODE字符集,使用這個選項會降低效率 
CANON_EQ:一個字符的實際存儲形式是經過編碼後的數字,使用CANON_EQ選項就可以匹配一個字母在各種編碼了。 
例如a可以匹配+00E0和U+0061U+0300 
使用這個選項會降低效率 
我們可以組合以上選項,只要使用|,進行按位或操作即可 
Java代碼  收藏代碼
  1. Pattern p =  
  2. Pattern.compile("t # a compound flag example",Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE|  
  3. Pattern.COMMENT);  

我們還要注意點的時Java對轉譯字符\的處理,例如我們要匹配一個數字: 
我們不能使用: 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile("\d");  

而是: 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile("\\d");  

另外如果regex本身形式是錯誤的,compile方法會拋出java.util.regex.PatternSyntaxException異常。 
下面我們總結一下public Matcher matcher(CharSequence input)方法: 
當我們使用compile操作,創建了Pattern對象之後,我們就可以使用Pattern對象的matcher操作,生成 
matcher對象了,Matcher對象包含了許多對匹配結果集的操作,我們在總結Matcher對象的時候再說。另外 
順便提一下參數CharSequence,CharBuffer, Segment, String, StringBuffer, StringBuilder 都實現了 
這個接口,所以參數可以是這些中的任一種類型了。 
下面我們看看: 
Java代碼  收藏代碼
  1. public int flags()  

這個方法返回了我們前面可以設置的並且已經設置的flags選項,我們通過按位與來判斷是否設置了某個選項: 
Java代碼  收藏代碼
  1. int flgs = myPattern.flags();  
  2. boolean isUsingCommentFlag =( Pattern.COMMENTS == (Pattern.COMMENTS & flgs)) ;  

看看一個簡化過程的方法: 
Java代碼  收藏代碼
  1. public static boolean matches (String regex,CharSequence input)  

這個方法實際上是: 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile(regex);  
  2. Matcher m = p.matcher(candidate);  
  3. m.matches()  

過程的一個簡化,我們在後面總結Matcher中的matches方法之後就會理解這個了。 
想必我們經常使用把字符串提取出token變成字符串數組的String中的split方法吧,下面我們看看 
類似的一個方法: 
public String[] split(CharSequence input) 
這個方法提供了強大的功能,因爲它可以使用正則表達式來作爲token的分割: 
Java代碼  收藏代碼
  1. Pattern p = new Pattern.compile(",|and");  
  2. String fruits[] = p.split("apple,banana and orange");  

split的一個重載的版本: 
Java代碼  收藏代碼
  1. public String[] split(CharSequence input, int limit)  

它指定了劃分的組數,有以下三種情況: 
limit==0 
這時候和沒有limit參數的那個split效果一樣 
limit>0 
如果你僅僅對前limit個感興趣,你可以使用limit: 
Java代碼  收藏代碼
  1. String[] tmp = pattern.split("Hello, Dolly, You, Are, My, Favorite",3);  
  2. //tmp[0] is  "Hello",  
  3. // tmp[1] is "Dolly";  
  4. //tmp[2] is  "You, Are, My, Favorite";  

limit<0 
會儘可能的劃分所有的組,即使分割符後面是個空字符,也要單獨生成一個token:"" 
Java代碼  收藏代碼
  1. Pattern p = Pattern.compile(",");  
  2. String temp[] = p.split("Hello,Dolly,", -1);  
  3. //temp[]={"Hello","Dolly",""}  

下次再總結Matcher類,和正則表達式的一些高級部分 
發佈了90 篇原創文章 · 獲贊 9 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章