這個系列的文章我們使用以下的順序進行講解:
-
詳解;Pattern
-
詳解;Matcher
- 正規表達式文法詳解。
接下來先來介紹
Pattern
類。
在Java中,
java.util.regex
包定義了正規表達式使用到的相關類,其中最主要的兩個類為:
Pattern
、
Matcher
:
-
編譯正規表達式後建立一個比對模式;Pattern
-
使用Matcher
執行個體提供的正規表達式對目标字元串進行比對,是真正影響搜尋的對象。。Pattern
另加一個新的例外類,PatternSyntaxException,當遇到不合法的搜尋模式時,會抛出例外。
Pattern 概述
聲明:public final class
Pattern
implements java.io.Serializable
Pattern 類有
final
修飾,可知他不能被子類繼承。
含義:模式類,正規表達式的編譯表示形式。
注意:此類的執行個體是不可變的,可供多個并發線程安全使用。
Pattern 比對模式(Pattern flags)
compile( )方法有一個版本,它需要一個控制正規表達式的比對行為的參數:
Pattern Pattern.compile(String regex, int flag)
flag 的取值範圍
字段 | 說明 |
---|---|
Pattern. | unix行模式,大多數系統的行都是以 結尾的,但是少數系統,比如Windows,卻是以 組合來結尾的,啟用這個模式之後,将會隻以 作為行結束符,這會影響到^、$和點号(點号比對換行符)。 通過嵌入式标志表達式 ( ) 也可以啟用 Unix 行模式。 |
Pattern. | 預設情況下,大小寫不敏感的比對隻适用于 字元集。這個标志能讓表達式忽略大小寫進行比對。要想對 字元進行大小不明感的比對,隻要将 與這個标志合起來就行了。 通過嵌入式标志表達式( )也可以啟用不區分大小寫的比對。 指定此标志可能對性能産生一些影響。 |
Pattern. ⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢⇢ | 這種模式下,比對時會忽略(正規表達式裡的)空格字元(不是指表達式裡的”//s”,而是指表達式裡的空格,tab,回車之類)和注釋(從#開始,一直到這行結束)。 通過嵌入式标志表達式( ) 也可以啟用注釋模式。 |
Pattern. | 預設情況下,輸入的字元串被看作是一行,即便是這一行中包好了換行符也被看作一行。當比對“^”到“$”之間的内容的時候,整個輸入被看成一個一行。啟用多行模式之後,包含換行符的輸入将被自動轉換成多行,然後進行比對。 通過嵌入式标志表達式 ( ) 也可以啟用多行模式。 |
Pattern. | 啟用字面值解析模式。 指定此标志後,指定模式的輸入字元串就會作為字面值字元序列來對待。輸入序列中的元字元或轉義序列不具有任何特殊意義。 标志 和 在與此标志一起使用時将對比對産生影響。其他标志都變得多餘了。 不存在可以啟用字面值解析的嵌入式标志字元。 |
Pattern. | 在這種模式中,表達式 可以比對任何字元,包括行結束符。預設情況下,此表達式不比對行結束符。 通過嵌入式标志表達式 ( ) 也可以啟用此種模式(s 是 “single-line” 模式的助記符,在 Perl 中也使用它)。 |
Pattern. | 在這個模式下,如果你還啟用了 标志,那麼它會對Unicode字元進行大小寫不敏感的比對。預設情況下,大小寫不明感的比對隻适用于US-ASCII字元集。 指定此标志可能對性能産生影響。 |
Pattern. | 當且僅當兩個字元的 都完全相同的情況下,才認定比對。比如用了這個标志之後,表達式 會比對 。預設情況下,不考慮 。 指定此标志可能對性能産生影響。 |
在這些标志裡面,
Pattern.CASE_INSENSITIVE
,
Pattern.MULTILINE
,以及
Pattern.COMMENTS
是最有用的(其中
Pattern.COMMENTS
還能幫我們把思路理清楚,并且/或者做文檔)。注意,你可以用在表達式裡插記号的方式來啟用絕大多數的模式。這些記号就在上面那張表的各個标志的下面。你希望模式從哪裡開始啟動,就在哪裡插記号。
可以用
OR
(
|
)運算符把這些标志配合使用。
代碼示例
多行模式:Pattern. MULTILINE
示例
MULTILINE
我測試了一下,也就是說如果沒有 MULTILINE 标志的話,
^
和
$
隻能比對輸入序列的開始和結束;否則,就可以比對輸入序列内部的行結束符。測試代碼如下:
import java.util.regex.*;
/**
* 多行模式
*/
public class ReFlags_MULTILINE {
public static void main(String[] args) {
// 注意裡面的換行符
String str = "hello world\r\n" + "hello java\r\n" + "hello java";
System.out.println("===========比對字元串開頭(非多行模式)===========");
Pattern p = Pattern.compile("^hello");
Matcher m = p.matcher(str);
while (m.find()) {
System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]");
}
System.out.println("===========比對字元串開頭(多行模式)===========");
p = Pattern.compile("^hello", Pattern.MULTILINE);
m = p.matcher(str);
while (m.find()) {
System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]");
}
System.out.println("===========比對字元串結尾(非多行模式)===========");
p = Pattern.compile("java$");
m = p.matcher(str);
while (m.find()) {
System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]");
}
System.out.println("===========比對字元串結尾(多行模式)===========");
p = Pattern.compile("java$", Pattern.MULTILINE);
m = p.matcher(str);
while (m.find()) {
System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]");
}
}
}
===========比對字元串開頭(非多行模式)===========
hello 位置:[,]
===========比對字元串開頭(多行模式)===========
hello 位置:[,]
hello 位置:[,]
hello 位置:[,]
===========比對字元串結尾(非多行模式)===========
java 位置:[,]
===========比對字元串結尾(多行模式)===========
java 位置:[,]
java 位置:[,]
忽略大小寫:Pattern. CASE_INSENSITIVE
示例
CASE_INSENSITIVE
有的時候,需要進行忽略大小寫的比對。該例子實作比對攝氏溫度和華氏溫度,對于以C、c、F和f結尾的溫度值都能比對。
import java.util.regex.Pattern;
public class ReFlags_CASE_INSENSITIVE {
public static void main(String[] args) {
System.out.println("===========API忽略大小寫===========");
String moneyRegex = "[+-]?(\\d)+(.(\\d)*)?(\\s)*[CF]";
Pattern p = Pattern.compile(moneyRegex,Pattern.CASE_INSENSITIVE);
System.out.println("-3.33c " + p.matcher("-3.33c").matches());
System.out.println("-3.33C " + p.matcher("-3.33C").matches());
System.out.println("===========不忽略大小寫===========");
moneyRegex = "[+-]?(\\d)+(.(\\d)*)?(\\s)*[CF]";
p = Pattern.compile(moneyRegex);
System.out.println("-3.33c " + p.matcher("-3.33c").matches());
System.out.println("-3.33C " + p.matcher("-3.33C").matches());
System.out.println("===========正則内部忽略大小寫===========");
moneyRegex = "[+-]?(\\d)+(.(\\d)*)?(\\s)*(?i)[CF]";
p = Pattern.compile(moneyRegex);
System.out.println("-3.33c " + p.matcher("-3.33c").matches());
System.out.println("-3.33C " + p.matcher("-3.33C").matches());
System.out.println("===========内部不忽略大小寫===========");
moneyRegex = "[+-]?(\\d)+(.(\\d)*)?(\\s)*[CF]";
p = Pattern.compile(moneyRegex);
System.out.println("-3.33c " + p.matcher("-3.33c").matches());
System.out.println("-3.33C " + p.matcher("-3.33C").matches());
}
}
===========API忽略大小寫===========
-c true
-C true
===========不忽略大小寫===========
-c false
-C true
===========正則内部忽略大小寫===========
-c true
-C true
===========内部不忽略大小寫===========
-c false
-C true
啟用注釋:Pattern. COMMENTS
示例
COMMENTS
啟用注釋,開啟之後,正規表達式中的空格以及#号行将被忽略。
import java.util.regex.Pattern;
public class ReFlags_COMMENTS {
public static void main(String[] args) {
System.out.println("===========API啟用注釋===========");
String comments = " (\\d)+#this is comments.";
Pattern p = Pattern.compile(comments, Pattern.COMMENTS);
System.out.println("1234 " + p.matcher("1234").matches());
System.out.println("===========不啟用注釋===========");
comments = " (\\d)+#this is comments.";
p = Pattern.compile(comments);
System.out.println("1234 " + p.matcher("1234").matches());
System.out.println("===========正則啟用注釋===========");
comments = "(?x) (\\d)+#this is comments.";
p = Pattern.compile(comments);
System.out.println("1234 " + p.matcher("1234").matches());
System.out.println("===========不啟用注釋===========");
comments = " (\\d)+#this is comments.";
p = Pattern.compile(comments);
System.out.println("1234 " + p.matcher("1234").matches());
}
}
===========API啟用注釋===========
true
===========不啟用注釋===========
false
===========正則啟用注釋===========
true
===========不啟用注釋===========
false
可以看到,#号到行尾的注釋部分和前面的空白字元都被忽略了。正規表達式内置的啟用注釋為(?x)。
啟用 dotall 模式:Pattern. DOTALL
示例
DOTALL
啟用dotall模式,一般情況下,點号(
.
)比對任意字元,但不比對換行符,啟用這個模式之後,點号還能比對換行符。
import java.util.regex.Pattern;
public class ReFlags_DOTALL {
public static void main(String[] args) {
System.out.println("===========API啟用DOTALL===========");
String dotall = "<xml>(.)*</xml>";
Pattern p = Pattern.compile(dotall, Pattern.DOTALL);
System.out.println("<xml>\\r\\n</xml> " + p.matcher("<xml>\r\n</xml>").matches());
System.out.println("===========不啟用DOTALL===========");
dotall = "<xml>(.)*</xml>";
p = Pattern.compile(dotall);
System.out.println("<xml>\\r\\n</xml> " + p.matcher("<xml>\r\n</xml>").matches());
System.out.println("===========正則啟用DOTALL===========");
dotall = "(?s)<xml>(.)*</xml>";
p = Pattern.compile(dotall);
System.out.println("<xml>\\r\\n</xml> " + p.matcher("<xml>\r\n</xml>").matches());
System.out.println("===========不啟用DOTALL===========");
dotall = "<xml>(.)*</xml>";
p = Pattern.compile(dotall);
System.out.println("<xml>\\r\\n</xml> " + p.matcher("<xml>\r\n</xml>").matches());
}
}
===========API啟用DOTALL===========
<xml>\r\n</xml> true
===========不啟用DOTALL===========
<xml>\r\n</xml> false
===========正則啟用DOTALL===========
<xml>\r\n</xml> true
===========不啟用DOTALL===========
<xml>\r\n</xml> false
平白字元模式 模式:Pattern. LITERAL
示例
LITERAL
啟用這個模式之後,所有元字元、轉義字元都被看成普通的字元,不再具有其他意義。
import java.util.regex.Pattern;
public class ReFlags_LITERAL {
public static void main(String[] args) {
System.out.println(Pattern.compile("\\d", Pattern.LITERAL).matcher("\\d").matches());// true
System.out.println(Pattern.compile("\\d", Pattern.LITERAL).matcher("2").matches());// false
System.out.println(Pattern.compile("(\\d)+", Pattern.LITERAL).matcher("1234").matches());// false
System.out.println(Pattern.compile("(\\d)+").matcher("1234").matches());// true
System.out.println(Pattern.compile("(\\d){2,3}", Pattern.LITERAL).matcher("(\\d){2,3}").matches());// true
}
}