Java正則表達式的簡單使用

前言

正則表達式是描述一組字符串的方法,它以這組字符串中的每個字符的共同特徵爲基礎。正則表達式可以用於搜索、編輯、操縱文本與數據。你應該學習一種特殊的語法來創建正則表達式,這種語法已經超出了Java編程語言標準的語法。正則表達式的變化很複雜,不過一旦你理解了它們是如何被構造的話,你就能解釋或者創建任意的正則表達式了。
java.util.regex包主要由Pattern、Matcher、 PatternSyntaxException類構成。

Pattern

Pattern對象表示一個已編譯的正則表達式。Pattern 類沒有提供公共的構造方法,要創建一個Pattern對象,首先必須調用公共的靜態 compile 方法。
public static Pattern compile(String regex):將給定的正則表達式編譯到Pattern中。
public static Pattern compile(String regex,int flags):將給定的正則表達式編譯到具有給定標誌的Pattern中。
常用標誌如下,(?X)是嵌入到正則表達式的標誌字符:
1、Pattern.CASE_INSENSITIVE(?i):默認情況下,大小寫不明感的匹配只適用於US-ASCII字符集,這個標誌能讓表達式忽略大小寫進行匹配。要想對Unicode字符進行大小不明感的匹配,只要將UNICODE_CASE與這個標誌合起來就行了。例如:Pattern.matches("(?i:Ab)","ab")。
2、Pattern.COMMENTS(?x)在這種模式下,匹配時會忽略正則表達式裏的空格字符,不是指表達式裏的"\s",而是指表達式裏的空格,tab,回車之類。註釋從#開始,一直到這行結束。例如:Pattern.matches("(?x:#這行是備註\na b)","ab")。
3、Pattern.DOTALL(?s)在這種模式下,表達式'.'可以匹配任意字符,包括表示一行的結束符,默認不匹配行的結束符。例如:Pattern.matches("(?s:.)","\n")。
4、Pattern.MULTILINE(?m):在這種模式下,'^'和'$'分別匹配一行的開始和結束。此外,'^'仍然匹配字符串的開始,'$'也匹配字符串的結束。默認情況下,這兩個表達式僅僅匹配字符串的開始和結束。
5、Pattern.UNICODE_CASE(?u): 在這個模式下,如果你還啓用了CASE_INSENSITIVE標誌,那麼它會對Unicode字符進行大小寫不明感的匹配。默認情況下,大小寫不明感的匹配只適用於US-ASCII字符集。
6、Pattern.UNIX_LINES(?d): 在這個模式下,只有'\n'才被認作一行的結束。
7、Pattern.LITERAL:指定此標誌後,指定Pattern的輸入字符串就會作爲字面值字符串來對待,輸入字符串中的元字符或轉義序列不具有任何特殊意義。 \Q和\E之間的字符串和這個模式作用一樣。例如:Pattern.matches("\\Q.*\\E",".*")。

典型的調用順序是:
Pattern p = Pattern.compile("a*b")
Matcher m = p.matcher("aaaaab")
boolean b = m.matches()

在僅使用一次正則表達式時,可以方便地通過此類定義 matches 方法,此方法編譯表達式並在單個調用中將輸入序列與其匹配。
boolean b = Pattern.matches("a*b", "aaaaab")

flags方法和pattern方法分別返回已編譯的Pattern的標誌和正則表達式。

split方法和string類的split方法一樣,將給定字符串按照正則表達式拆分成數組。可以帶一個參數或者兩個參數,第二個參數n默認是0。如果n 大於零,那麼模式至多應用 n-1 次,數組的長度不大於 n,並且數組的最後條目將包含除最後的匹配定界符之外的所有輸入。如果 n 非正,那麼將應用模式的次數不受限制,並且數組可以爲任意長度。如果 n 爲零,那麼應用模式的次數不受限制,數組可以爲任意長度,並且將丟棄尾部空字符串。

quote方法返回指定字符串的字面值模式字符串,即返回\Q\E這樣的字符串。

Matcher

Matcher是一個解釋Pattern和對輸入字符串進行匹配操作的引擎。與 Pattern 相似,Matcher 也沒有定義公共的構造方法,通過調用 Pattern 對象的matcher方法來獲得一個 Matcher 對象:
Pattern pattern = Pattern.compile("abcd");
Matcher matcher = pattern.matcher("abcd");
默認是在整個輸入序列中匹配,但是可以調用region方法設置輸入序列中的一部分作爲匹配區域。Matcher的顯式狀態包括最近成功匹配的開始和結束索引,由start和end方法獲取。它還包括模式中每個捕獲組捕獲的輸入子序列的開始(start(int group索引))和結束(end(int group索引))索引以及該子序列的總數(groupCount方法)。group方法還可以返回每個捕獲組捕獲的字符串,group(0)始終代表整個匹配,從group(1)開始纔是捕獲組。groupCount爲0代表沒有捕獲組。Matcher的 reset() 方法重置Matcher,如果需要重新輸入序列,則調用其 reset(CharSequence) 方法,重置Matcher將放棄其顯式狀態信息。
Matcher有三個匹配方法,matches、lookingAt、find,每個方法都返回一個表示成功或失敗的布爾值。
matches:和Pattern.matches靜態方法一樣,將整個輸入與正則進行匹配,整個字符串符合正則表達式,才返回true。
lookingAt:將輸入從頭開始與正則匹配,用來檢測字符串的開頭部分是否符合正則表達式,如果符合,返回true。
find:從當前位置開始匹配,找到一個匹配的字符串,下次匹配的位置將會變爲匹配字符串最後一位的後面。

    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("(\\d+)");
        Matcher matcher = pattern.matcher("123a4567b90d");
        while (matcher.find()) {
            System.out.println(matcher.group(1));
            System.out.println("匹配到的字符串開始索引:" + matcher.start());
            System.out.println("匹配到的字符串結束索引:" + (matcher.end() - 1));
        }
    }
123
匹配到的字符串開始索引:0
匹配到的字符串結束索引:2
4567
匹配到的字符串開始索引:4
匹配到的字符串結束索引:7
90
匹配到的字符串開始索引:9
匹配到的字符串結束索引:10

PatternSyntaxException

對象是一個未檢查異常,表示正則表達式的一個語法錯誤。


構造摘要


行結束符

行結束符 是一個或兩個字符的序列,標記輸入字符序列的行結尾。以下代碼被識別爲行結束符:
新行(換行)符 ('\n')
後面緊跟新行符的回車符 ("\r\n")
單獨的回車符 ('\r')
下一行字符 ('\u0085')
行分隔符 ('\u2028') 
段落分隔符 ('\u2029)
如果指定 UNIX_LINES(?d)標誌,則新行符('\n')是唯一識別的行結束符。 
如果指定 DOTALL 標誌,則正則表達式 . 可以與任何字符包括行結束符除外匹配。 
默認情況下,正則表達式 ^ 和 $ 忽略行結束符,僅分別與整個輸入序列的開頭和結尾匹配。如果指定MULTILINE標誌,則 ^ 在輸入的開頭和行結束符之後發生匹配,$ 在輸入的結尾和行結束符之前匹配。

邏輯運算

XY:X 後面跟着 Y
X|Y:X或Y

字符

正則表達式 描述 例子
x x代表的字符 Pattern.matches("a", "a")
\\ 反斜槓字符 Pattern.matches("\\\\", "\\")
\0n 8進制值n,Unicode碼點等於此值的字符(0 <= n <= 7) Pattern.matches("\\00", (char) 0 + "")
\0nn 8進制值nn,Unicode碼點等於此值的字符(0 <= n <= 7) Pattern.matches("\\061", "1")
\0mnn 8進制值mnn,Unicode碼點等於此值的字符(0 <= m <= 3、0 <= n <= 7) Pattern.matches("\\0377", "ÿ")
\xhh 16進制值hh,Unicode碼點等於此值的字符 Pattern.matches("\\x31", "1")
\uhhhh 16進制值hhhh,Unicode碼點等於此值的字符 Pattern.matches("\\u597D", "好")
\x{h...h} 16進制值{h...h},Unicode碼點等於此值的字符,支持輔助平面字符 Pattern.matches("\\x{597D}", "好")
\t 製表符 ('\u0009') Pattern.matches("\\u0009", "\t")
\n 換行符 ('\u000A') Pattern.matches("\\u000A", "\n")
\r 回車符 ('\u000D') Pattern.matches("\\u000D", "\r")
\f 換頁符 ('\u000C') Pattern.matches("\\u000C", "\f")
\a 報警符 ('\u0007') Pattern.matches("\\u0007", "\a")
\e 轉義符 ('\u001B') Pattern.matches("\\u001B", "\e")


字符類別

正則表達式 描述 例子
[abc] a,,b 或c Pattern.matches("[abc]", "a")
[^abc] 除a,,b或c之外的任意字符 Pattern.matches("[^abc]", "d")
[a-zA-Z] a到z或A到Z Pattern.matches("[a-zA-Z]", "a")
[a-d[m-p]] a到d或m到p,相當於[a-dm-p],並集 Pattern.matches("[a-d[m-p]]", "a")
[a-z&&[def]] d、e或f,交集 Pattern.matches("[a-z&&[def]]", "d")
[a-z&&[^bc]] a到z中除了b和c,相當於[ad-z] Pattern.matches("[a-z&&[^bc]]", "d")
[a-z&&[^m-p]] a-z中除了m到p,相當於:[a-lq-z] Pattern.matches("[a-z&&[^m-p]]", "d")


預定義字符類別

正則表達式 描述
. 任何字符(與行結束符可能匹配也可能不匹配)
\d 數字:[0-9]
\D 非數字: [^\d]
\h 水平空白字符:[ \t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]
\H 非水平空白字符
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\v 垂直空白字符:[\n\x0B\f\r\x85\u2028\u2029]
\V 非垂直空白字符
\w 單詞字符:[a-zA-Z_0-9]
\W 非單詞字符:[^\w]


邊界匹配器

正則表達式 描述
^ 匹配行的開頭,受多行模式影響
$ 匹配行的結尾,受多行模式影響
\b 單詞邊界
\B 非單詞邊界
\b:單詞和符號之間的邊界。
\B:不是\b的邊界都屬於\B,比如單詞和單詞的邊界,符號和符號的邊界。
這裏的單詞不是\w代表的0-9a-zA-Z_,我猜想應該是w的超集,包括比如漢字、希臘字母、英文字母、數字、下劃線等等,符號可以是中文符號、英文符號、空格、製表符、換行符等等,更具體的包括哪些只能在實踐中測試。參考下面的例子:
public static void main(String[] args) {  
        String str = "(我(i ——\t_離";  
        String rex = "\\b";  
        Pattern pattern = Pattern.compile(rex);  
        String[] result = pattern.split(str);  
        for (String string : result) {  
            System.out.println("分割的字符串:" + "[" + string + "]");  
        }  
    }  
分割的字符串:[(]  
分割的字符串:[我]  
分割的字符串:[(]  
分割的字符串:[i]  
分割的字符串:[ —— ]  
分割的字符串:[_離]  

public static void main(String[] args) {  
        String str = "(我(i ——\t_離";  
        String rex = "\\B";  
        Pattern pattern = Pattern.compile(rex);  
        String[] result = pattern.split(str);  
        for (String string : result) {  
            System.out.println("分割的字符串:" + "[" + string + "]");  
        }  
    }  
分割的字符串:[]  
分割的字符串:[(我(i ]  
分割的字符串:[—]  
分割的字符串:[—]  
分割的字符串:[    _]  
分割的字符串:[離]  


轉義

反斜槓用於引進轉義構造,還可以用於引用特殊字符,例如\\代表反斜槓,\(代表左圓括號。


捕獲組

捕獲組是通過從左到右計算其圓括號來編號的。例如,在表達式 ((A)(B(C))) 中,存在四個這樣的組:((A)(B(C)))、(A)、(B(C))、(C),組編號0始終代表整個匹配。之所以這樣命名捕獲組是因爲在匹配中,保存了與這些組匹配的輸入序列的每個子序列。捕獲的子序列稍後可以通過 Back 引用在表達式中使用,也可以在匹配操作完成後調用Matcher類的group方法獲取。

非捕獲組

非捕獲組,它只分組而不捕獲文本,也就不佔用分組編號,普通非捕獲組的語法是(?:X),X是正則表達式構造。

數量詞

Greedy

X?   X,一次或一次也沒有
X*   X,零次或多次
X+   X,一次或多次
X{n}  X,恰好 n 次
X{n,}   X,至少 n 次
X{n,m}  X,至少 n 次,但是不超過 m 次
public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("沒匹配");
    }
輸出:0-10
解釋:Greedy是儘量吃入後再吐出。這個表達式 {3,10}吃入最多字符的10個字符:abcd1efgh2。吃入之後後面的[0-9]發現沒有匹配的,吐出最後一個字符看是數字結果匹配。

Reluctant
X??   X,一次或一次也沒有
X*?   X,零次或多次
X+?   X,一次或多次
X{n}?   X,恰好 n 次
X{n,}?   X,至少 n 次
X{n,m}?   X,至少 n 次,但是不超過 m 次
public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}?[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("沒匹配");
    }
輸出:0-5
解釋:對於Reluctant 來說,就是Greedy的一個相反的匹配模式,他從左到有一個一個開始吃入,而不是整個字符串一個一個吐出。這個表達式{3,10}的吞入最少字符的3個字符:abc,吃入之後後面的[0-9]發現沒有匹配的,再吃入1個字符後纔有匹配。

Possessive
X?+   X,一次或一次也沒有
X*+   X,零次或多次
X++   X,一次或多次
X{n}+   X,恰好 n 次
X{n,}+   X,至少 n 次
X{n,m}+   X,至少 n 次,但是不超過 m 次
 public static void main(String[] args) {
        Pattern p = Pattern.compile(".{3,10}+[0-9]");
        String s = "abcd1efgh2";
        Matcher m = p.matcher(s);
        if (m.find())
            System.out.println(m.start() + "-" + m.end());
        else
            System.out.println("沒匹配");
    }
輸出:沒匹配
它和greedy類似,也是全部吃入,但是唯一不同的是它不吐出。


先行斷言和後行斷言

先行斷言和後行斷言其實就是預測之後的字符和之前的字符,只有首先符合預測結果,才能繼續匹配,在預測過程中,匹配的位置不會變化,所以被稱爲“零寬”。例如,預測a後面是bc,那麼所有a後面是bc的字符串符合,接着正常匹配,匹配位置依然從a後面開始而不是從c開始。以下4種都屬於特殊結構的非捕獲組。

(?=pattern) 正向先行斷言 :代表字符串中的一個位置,緊接該位置之後的字符序列能夠匹配pattern。
例如:Pattern.matches("a(?=b)bc", "abc")返回true。

(?!pattern) 負向先行斷言 :代表字符串中的一個位置,緊接該位置之後的字符序列不能匹配pattern。
例如:Pattern.matches("a(?!bcd)bc", "abc")返回true,Pattern.matches("a(?!bc)bc", "abc")返回false。

 (?<=pattern) 正向後行斷言 :代表字符串中的一個位置,緊接該位置之前的字符序列能夠匹配pattern。
例如:Pattern.matches("a(?<=a)bc", "abc")返回true。

(?<!pattern) 負向後行斷言 :代表字符串中的一個位置,緊接該位置之前的字符序列不能匹配pattern。
例如:Pattern.matches("a(?<!ab)bc", "abc")返回true,Pattern.matches("a(?<!a)bc", "abc")返回false。


開啓關閉特殊標誌

這裏的標誌就是Pattern類裏的區分大小寫、多行模式等。Pattern中大部分標誌可以使用嵌入式字符串,也可以使用Pattern的常量進行設置。嵌入式字符串直接嵌入在正則表達式裏,可以控制開啓和關閉、是否捕獲。標誌前加“-”表示關閉。
(?idmsux-idmsux) :將開啓或者關閉標誌i d m s u x。
(?idmsux-idmsux:X):將開啓或者關閉標誌i d m s u x,僅對X有效,但是X是作爲非捕獲組。
例如:Pattern.matches("(?i)abc(?-i)abc", "aBCabc")返回true,Pattern.matches("(?i)abc(?-i)abc", "aBCaBc")返回false。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章