java正則表達式學習筆記

Java 正則表達式語法

爲了更有效的使用正則表達式,須要瞭解正則表達式語法。正則表達式語法很複雜,能夠寫出很是高級的表達式。只有經過大量的練習才能掌握這些語法規則。java

本篇文字,咱們將經過例子瞭解正則表達式語法的基礎部分。介紹重點將會放在爲了使用正則表達式所須要瞭解的核心概念,不會涉及過多的細節。詳細解釋,參見 Java DOC 中的 Pattern 類.正則表達式

基本語法

在介紹高級功能前,咱們先快速瀏覽下正則表達式的基本語法。數組

字符

是正則表達式中最常用的的一個表達式,做用是簡單的匹配一個肯定的字符。例如:
John
這個簡單的表達式將會在一個輸入文本中匹配John文本。
能夠在表達式中使用任意英文字符。也可使用字符對於的8進制,16進制或unicode編碼表示。例如:
101
\x41
\u0041

以上3個表達式 都表示大寫字符A。第一個是8進制編碼(101),第2個是16進制編碼(41),第3個是unicode編碼(0041).app

字符分類

字符分類是一種結構,能夠針對多個字符匹配而不僅是一個字符。換句話說,一個字符分類匹配輸入文本中的一個字符,對應字符分類中多個容許字符。例如,你想匹配字符 a,b 或c,表達式以下:
[abc]this

用一對方括號[] 表示字符分類。方括號自己並非要匹配的一部分。編碼

能夠用字符分類完成不少事。例如想要匹配單詞John,首字母能夠爲大寫和小寫J.
[Jj]ohnspa

字符分類[Jj] 匹配J或j,剩餘的 ohn 會準確匹配字符ohn..net

預約義字符分類

正則表達式中有一些預約義的字符分類可使用。例如, \d 表示任意數字, \s 表示任意空白字符,\w 表示任意單詞字符。
預約義字符分類不須要括在方括號裏,固然也能夠組合使用
\d
[\d\s]

第1個匹配任意數字,第2個匹配任意數字或空白符。
完整的預約義字符分類列表,在本文最後列出。code

邊界匹配

正則表達式支持匹配邊界,例如單詞邊界,文本的開頭或末尾。例如,\w 匹配一個單詞,^匹配行首,$ 匹配行尾。
^This is a single line$
上面的表達式匹配一行文本,只有文本 This is a single line。注意其中的行首和行尾標誌,表示不能有任何文本在文本的前面後後面,只能是行首和行尾。
完整的匹配邊界列表,在本文最後列出。對象

量詞匹配

量詞能夠匹配一個表達式屢次出現。例以下列表達式匹配字母A 出現0次或屢次。
A*

量詞 * 表示0次或屢次。+ 表示1次或屢次。? 表示0次或1次。還有些其餘量詞,參見本文後面的列表。

量詞匹配分爲 飢餓模式,貪婪模式,獨佔模式。飢餓模式 匹配儘量少的文本。貪婪模式匹配儘量多的文本。獨佔模式匹配儘量多的文本,甚至致使剩餘表達式匹配失敗。

如下演示飢餓模式,貪婪模式,獨佔模式區別。假設如下文本:
John went for a walk, and John fell down, and John hurt his knee.

飢餓模式下 表達式:
John.*?
這個表達式匹配John 後跟0個或多個字符。 . 表示任意字符。* 表示0或屢次。? 跟在 * 後面,表示 * 採用飢餓模式。
飢餓模式下,量詞只會匹配儘量少的字符,即0個字符。上例中的表達式將會匹配單詞John,在輸入文本中出現3次。

若是改成貪婪模式,表達式以下:
John.*
貪婪模式下,量詞會匹配儘量多的字符。如今表達式會匹配第一個出現的John,以及在貪婪模式下 匹配剩餘的全部字符。這樣,只有一個匹配項。

最後,咱們改成獨佔模式:
John.*+hurt
*後跟+ 表示獨佔模式量詞。

這個表達式在輸入文本中沒有匹配項,儘管文本中包括 John 和 hurt. 爲何會這樣? 由於 .*+ 是獨佔模式。與貪婪模式下,儘量多的匹配文本,以使整個表達式匹配不一樣。獨佔模式會盡量的多的匹配,但不考慮表達式剩餘部分是否能匹配上。

.*+ 將會匹配第一個John以後的全部字符,這會致使表達式中剩餘的 hurt 沒有匹配項。若是改成貪婪模式,會有一個匹配項。表達式以下:
John.*hurt

邏輯操做符

正則表達式支持少許的邏輯運算(與,或,非)。
與操做是默認的,表達式 John ,意味着J 與 o與h與n。
或操做須要顯示指定,用 | 表示。例如表達式 John|hurt 意味着John 或 hurt 。

字符

. 任意英文字母
\\ 反斜槓, 單獨的反斜槓作爲轉義字符,與其餘特殊字符一塊兒使用。若是想匹配反斜槓自己,須要轉義。兩個反斜槓實際匹配一個反斜槓n字符的8進製表示.n 在0至7之間取值
nn 字符的8進製表示.n 在0至7之間取值
mnn 字符的8進製表示. m 在0至3之間取值, n 在0至7之間取值
\xhh 字符的16進製表示.
\uhhh 字符的16進製表示 0xhhhh. 對應unicode 編碼字符
\t 縮進符.
\n 換行符 (unicode: ‘\u000A’)
\r 回車符 (unicode: ‘\u000D’)
\f 製表符 (unicode: ‘\u000C’)
\a 警報(鈴聲)字符 (unicode: ‘\u0007’)
\e 轉義符 (unicode: ‘\u001B’)
\cx 控制符x

字符分類

[abc] 匹配 a, 或 b 或 c
[^abc] 匹配不是a,b,c 的字符,是否認匹配
[a-zA-Z] 匹配a 到 z ,A到Z 直接的字符,是範圍匹配
[a-d[m-p]] 匹配a到d之間字符或 m到p之間字符,是並集匹配
[a-z&&[def]] 匹配 d, e, 或 f. 是交集匹配 (這裏是在範圍 a-z和字符def之間取交集).
[a-z&&[^bc]] 匹配a-z 之間全部字符,排除bc的字符。是減法匹配
[a-z&&[^m-p]] 匹配a-z 之間全部字符,排除m-p之間的字符是減法匹配

內置字符分類

. 匹配任意一個字符,根據建立Pattern是傳入的標誌,可能匹配行結尾符
\d 匹配任意數字 [0-9]
\D 匹配任意非數字 [^0-9]
\s 匹配任意空白符 (空格, 縮進, 換行,回車)
\S 匹配任意非空白符
\w 匹配任意單詞
\W 匹配任意非單詞

邊界匹配

^ 匹配行首
$ 匹配行尾
\b 匹配單詞邊界
\B 匹配非單詞邊界
\A 匹配文本開頭
\G 匹配前一匹配項結尾
\Z Matches the end of the input text except the final terminator if any
\z 匹配文本結尾

量詞

貪婪模式 飢餓模式 獨佔模式  
X? X?? X?+ 匹配0或1次
X* X*? X*+ 匹配0或屢次
X+ X+? X++ 匹配1或屢次
X{n} X{n}? X{n}+ 匹配n次
X{n,} X{n,}? X{n,}+ 匹配最少n次
X{n, m} X{n, m}? X{n, m}+ 匹配最少n次,最多m次

正則表達式示例

下面是一個簡單的Java正則表達式的例子,用於在文本中搜索 http://

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 String pattern = ".*http://.*";
5 boolean matches = Pattern.matches(pattern, text);
6 System.out.println("matches = " + matches);

示例代碼實際上沒有檢測找到的 http:// 是不是一個合法超連接的一部分,如包含域名和後綴(.com,.net 等等)。代碼只是簡單的查找字符串 http:// 是否出現。

Java6 中關於正則表達式的API

本教程介紹了Java6 中關於正則表達式的API。

Pattern (java.util.regex.Pattern)

類 java.util.regex.Pattern 簡稱 Pattern, 是Java正則表達式API中的主要入口,不管什麼時候,須要使用正則表達式,從Pattern 類開始

Pattern.matches()

檢查一個正則表達式的模式是否匹配一段文本的最直接方法是調用靜態方法Pattern.matches(),示例以下:

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the pattern.";
4 String pattern = ".*is.*";
5 boolean matches = Pattern.matches(pattern, text);
6 System.out.println("matches = " + matches);

上面代碼在變量 text 中查找單詞 「is」 是否出現,容許」is」 先後包含 0或多個字符(由 .* 指定)
Pattern.matches() 方法適用於檢查 一個模式在一個文本中出現一次的狀況,或適用於Pattern類的默認設置。

若是須要匹配屢次出現,甚至輸出不一樣的匹配文本,或者只是須要非默認設置。須要經過Pattern.compile() 方法獲得一個Pattern 實例。

Pattern.compile()

若是須要匹配一個正則表達式在文本中屢次出現,須要經過Pattern.compile() 方法建立一個Pattern對象。示例以下:

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 String patternString = ".*http://.*";
5 Pattern pattern = Pattern.compile(patternString);

能夠在Compile 方法中,指定一個特殊標誌:
Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
Pattern 類包含多個標誌(int 類型),這些標誌能夠控制Pattern 匹配模式的方式。上面代碼中的標誌使模式匹配是忽略大小寫

Pattern.matcher()

一旦得到了Pattern對象,接着能夠得到Matcher對象。Matcher 示例用於匹配文本中的模式.示例以下
Matcher matcher = pattern.matcher(text);

Matcher類有一個matches()方法,能夠檢查文本是否匹配模式。如下是關於Matcher的一個完整例子

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 String patternString = ".*http://.*";
5 Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
6 Matcher matcher = pattern.matcher(text);
7 boolean matches = matcher.matches();
8 System.out.println("matches = " + matches);

Pattern.split()

Pattern 類的 split()方法,能夠用正則表達式做爲分隔符,把文本分割爲String類型的數組。示例:

1 String text = "A sep Text sep With sep Many sep Separators";
2 String patternString = "sep";
3 Pattern pattern = Pattern.compile(patternString);
4 String[] split = pattern.split(text);
5 System.out.println("split.length = " + split.length);
6 for(String element : split){
7     System.out.println("element = " + element);
8 }

上例中把text 文本分割爲一個包含5個字符串的數組。

Pattern.pattern()

Pattern 類的 pattern 返回用於建立Pattern 對象的正則表達式,示例:

 1 String patternString = "sep"; 2 Pattern pattern = Pattern.compile(patternString); 3 String pattern2 = pattern.pattern(); 

上面代碼中 pattern2 值爲sep ,與patternString 變量相同。

Matcher (java.util.regex.Matcher)

java.util.regex.Matcher 類用於匹配一段文本中屢次出現一個正則表達式,Matcher 也適用於多文本中匹配同一個正則表達式。

Matcher 有不少有用的方法,詳細請參考官方JavaDoc。這裏只介紹核心方法。

如下代碼演示如何使用Matcher

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 String patternString = ".*http://.*";
5 Pattern pattern = Pattern.compile(patternString);
6 Matcher matcher = pattern.matcher(text);
7 boolean matches = matcher.matches();

首先建立一個Pattern,而後獲得Matcher ,調用matches() 方法,返回true 表示模式匹配,返回false表示不匹配。
能夠用Matcher 作更多的事。

建立Matcher

經過Pattern 的matcher() 方法建立一個Matcher。

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 
5 String patternString = ".*http://.*";
6 Pattern pattern = Pattern.compile(patternString);
7 Matcher matcher = pattern.matcher(text);

matches()

Matcher 類的 matches() 方法用於在文本中匹配正則表達式

boolean  matches = matcher.matches();

若是文本匹配正則表達式,matches() 方法返回true。不然返回false。

matches() 方法不能用於查找正則表達式屢次出現。若是須要,請使用find(), start() 和 end() 方法。

lookingAt()

lookingAt() 與matches() 方法相似,最大的不一樣是,lookingAt()方法對文本的開頭匹配正則表達式;而
matches() 對整個文本匹配正則表達式。換句話說,若是正則表達式匹配文本開頭而不匹配整個文本,lookingAt() 返回true,而matches() 返回false。 示例:

1 String text    =
2         "This is the text to be searched " +
3         "for occurrences of the http:// pattern.";
4 String patternString = "This is the";
5 Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
6 Matcher matcher = pattern.matcher(text);
7 System.out.println("lookingAt = " + matcher.lookingAt());
8 System.out.println("matches   = " + matcher.matches());

上面的例子分別對文本開頭和整個文本匹配正則表達式 「this is the」. 匹配文本開頭的方法(lookingAt()) 返回true。

對整個文本匹配正則表達式的方法 (matches()) 返回false,由於 整個文本包含多餘的字符,而 正則表達式要求文本精確匹配」this is the」,先後又不能有額外字符。

find() + start() + end()

find() 方法用於在文本中查找出現的正則表達式,文本是建立Matcher時,經過 Pattern.matcher(text) 方法傳入的。若是在文本中屢次匹配,find() 方法返回第一個,以後每次調用 find() 都會返回下一個。

start() 和 end() 返回每次匹配的字串在整個文本中的開始和結束位置。實際上, end() 返回的是字符串末尾的後一位,這樣,能夠在把 start() 和 end() 的返回值直接用在String.substring() 裏。

 1 String text    =
 2         "This is the text which is to be searched " +
 3         "for occurrences of the word 'is'.";
 4 String patternString = "is";
 5 Pattern pattern = Pattern.compile(patternString);
 6 Matcher matcher = pattern.matcher(text);
 7 int count = 0;
 8 while(matcher.find()) {
 9     count++;
10     System.out.println("found: " + count + " : "  + matcher.start() + " - " + matcher.end());
11 }

這個例子在文本中找到模式 「is」 4次,輸出以下:

 found: 1 : 2 - 4
 found: 2 : 5 - 7
 found: 3 : 23 - 25
 found: 4 : 70 - 72

  

reset()

reset() 方法會重置Matcher 內部的 匹配狀態。當find() 方法開始匹配時,Matcher 內部會記錄截至當前查找的距離。調用 reset() 會從新從文本開頭查找。

也能夠調用 reset(CharSequence) 方法. 這個方法重置Matcher,同時把一個新的字符串做爲參數傳入,用於代替建立 Matcher 的原始字符串。

group()

假設想在一個文本中查找URL連接,而且想把找到的連接提取出來。固然能夠經過 start()和 end()方法完成。可是用group()方法更容易些。

分組在正則表達式中用括號表示,例如:
(John)
此正則表達式匹配John, 括號不屬於要匹配的文本。括號定義了一個分組。當正則表達式匹配到文本後,能夠訪問分組內的部分。

使用group(int groupNo) 方法訪問一個分組。一個正則表達式能夠有多個分組。每一個分組由一對括號標記。想要訪問正則表達式中某分組匹配的文本,能夠把分組編號傳入 group(int groupNo)方法。

group(0) 表示整個正則表達式,要得到一個有括號標記的分組,分組編號應該從1開始計算。

1 String text    =  "John writes about this, and John writes about that," +
2                         " and John writes about everything. "  ;
3 String patternString1 = "(John)";
4 Pattern pattern = Pattern.compile(patternString1);
5 Matcher matcher = pattern.matcher(text);
6 while(matcher.find()) {
7     System.out.println("found: " + matcher.group(1));
8 }
 以上代碼在文本中搜索單詞John.從每一個匹配文本中,提取分組1,就是由括號標記的部分。輸出以下
 found: John
 found: John
 found: John

  

多分組

上面提到,一個正則表達式能夠有多個分組,例如:
(John) (.+?)
這個表達式匹配文本」John」 後跟一個空格,而後跟1個或多個字符,最後跟一個空格。你可能看不到最後的空格。

這個表達式包括一些字符有特別意義。字符 點 . 表示任意字符。 字符 + 表示出現一個或多個,和. 在一塊兒表示 任何字符,出現一次或屢次。字符? 表示 匹配儘量短的文本。

完整代碼以下

 1 String text    =
 2           "John writes about this, and John Doe writes about that," +
 3                   " and John Wayne writes about everything."
 4         ;
 5 String patternString1 = "(John) (.+?) ";
 6 Pattern pattern = Pattern.compile(patternString1);
 7 Matcher matcher = pattern.matcher(text);
 8 while(matcher.find()) {
 9     System.out.println("found: " + matcher.group(1) +
10                        " "       + matcher.group(2));
11 }
注意代碼中引用分組的方式。代碼輸出以下
 found: John writes
 found: John Doe
 found: John Wayne

  

嵌套分組

在正則表達式中分組能夠嵌套分組,例如
((John) (.+?))
這是以前的例子,如今放在一個大分組裏.(表達式末尾有一個空格)。

當遇到嵌套分組時, 分組編號是由左括號的順序肯定的。上例中,分組1 是那個大分組。分組2 是包括John的分組,分組3 是包括 .+? 的分組。當須要經過groups(int groupNo) 引用分組時,瞭解這些很是重要。

如下代碼演示如何使用嵌套分組

 1 String text    =
 2           "John writes about this, and John Doe writes about that," +
 3                   " and John Wayne writes about everything."
 4         ;
 5 String patternString1 = "((John) (.+?)) ";
 6 Pattern pattern = Pattern.compile(patternString1);
 7 Matcher matcher = pattern.matcher(text);
 8 while(matcher.find()) {
 9     System.out.println("found:   ");
10 }
 輸出以下
 found:
 found:
 found: 

  

replaceAll() + replaceFirst()

replaceAll() 和 replaceFirst() 方法能夠用於替換Matcher搜索字符串中的一部分。replaceAll() 方法替換所有匹配的正則表達式,replaceFirst() 只替換第一個匹配的。

在處理以前,Matcher 會先重置。因此這裏的匹配表達式從文本開頭開始計算。

示例以下

 1 String text    =
 2           "John writes about this, and John Doe writes about that," +
 3                   " and John Wayne writes about everything."
 4         ;
 5 String patternString1 = "((John) (.+?)) ";
 6 Pattern pattern = Pattern.compile(patternString1);
 7 Matcher matcher = pattern.matcher(text);
 8 
 9 String replaceAll = matcher.replaceAll("Joe Blocks ");
10 System.out.println("replaceAll   = " + replaceAll);
11 
12 String replaceFirst = matcher.replaceFirst("Joe Blocks ");
13 System.out.println("replaceFirst = " + replaceFirst);

輸出以下
replaceAll = Joe Blocks about this, and Joe Blocks writes about that,
and Joe Blocks writes about everything.
replaceFirst = Joe Blocks about this, and John Doe writes about that,
and John Wayne writes about everything.

輸出中的換行和縮進是爲了可讀而增長的。

注意第1個字符串中全部出現 John 後跟一個單詞 的地方,都被替換爲 Joe Blocks 。第2個字符串中,只有第一個出現的被替換。

appendReplacement() + appendTail()

appendReplacement() 和 appendTail() 方法用於替換輸入文本中的字符串短語,同時把替換後的字符串附加到一個 StringBuffer 中。

當find() 方法找到一個匹配項時,能夠調用 appendReplacement() 方法,這會致使輸入字符串被增長到StringBuffer 中,並且匹配文本被替換。 從上一個匹配文本結尾處開始,直到本次匹配文本會被拷貝。

appendReplacement() 會記錄拷貝StringBuffer 中的內容,能夠持續調用find(),直到沒有匹配項。

直到最後一個匹配項目,輸入文本中剩餘一部分沒有拷貝到 StringBuffer. 這部分文本是從最後一個匹配項結尾,到文本末尾部分。經過調用 appendTail() 方法,能夠把這部份內容拷貝到 StringBuffer 中.

 1 String text    =
 2           "John writes about this, and John Doe writes about that," +
 3                   " and John Wayne writes about everything."
 4         ;
 5 
 6 String patternString1 = "((John) (.+?)) ";
 7 Pattern      pattern      = Pattern.compile(patternString1);
 8 Matcher      matcher      = pattern.matcher(text);
 9 StringBuffer stringBuffer = new StringBuffer();
10 
11 while(matcher.find()){
12     matcher.appendReplacement(stringBuffer, "Joe Blocks ");
13     System.out.println(stringBuffer.toString());
14 }
15 matcher.appendTail(stringBuffer);
16 System.out.println(stringBuffer.toString());
 注意咱們在while循環中調用appendReplacement() 方法。在循環完畢後調用appendTail()。
 代碼輸出以下:
 Joe Blocks
 Joe Blocks about this, and Joe Blocks
 Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
 Joe Blocks about this, and Joe Blocks writes about that, and Joe Blocks
 writes about everything.
相關文章
相關標籤/搜索