Java正則表達(dá)式之Pattern類實(shí)例詳解
前言
這個(gè)系列的文章我們使用以下的順序進(jìn)行講解:
- Pattern 詳解;
- Matcher 詳解;
- 正則表達(dá)式語(yǔ)法詳解。
接下來(lái)先來(lái)介紹 Pattern 類。
在Java中,java.util.regex包定義了正則表達(dá)式使用到的相關(guān)類,其中最主要的兩個(gè)類為:Pattern、Matcher:
- Pattern 編譯正則表達(dá)式后創(chuàng)建一個(gè)匹配模式;
- Matcher 使用Pattern實(shí)例提供的正則表達(dá)式對(duì)目標(biāo)字符串進(jìn)行匹配,是真正影響搜索的對(duì)象。。
另加一個(gè)新的例外類,PatternSyntaxException,當(dāng)遇到不合法的搜索模式時(shí),會(huì)拋出例外。
Pattern 概述
聲明:public final class Pattern implements java.io.Serializable
Pattern 類有final修飾,可知他不能被子類繼承。
含義:模式類,正則表達(dá)式的編譯表示形式。
注意:此類的實(shí)例是不可變的,可供多個(gè)并發(fā)線程安全使用。
Pattern 匹配模式(Pattern flags)
compile( )方法有一個(gè)版本,它需要一個(gè)控制正則表達(dá)式的匹配行為的參數(shù):
Pattern Pattern.compile(String regex, int flag)
flag 的取值范圍
字段 | 說(shuō)明 |
---|---|
Pattern.UNIX_LINES | unix行模式,大多數(shù)系統(tǒng)的行都是以\n結(jié)尾的,但是少數(shù)系統(tǒng),比如Windows,卻是以\r\n組合來(lái)結(jié)尾的,啟用這個(gè)模式之后,將會(huì)只以\n作為行結(jié)束符,這會(huì)影響到^、$和點(diǎn)號(hào)(點(diǎn)號(hào)匹配換行符)。 通過(guò)嵌入式標(biāo)志表達(dá)式 (?d) 也可以啟用 Unix 行模式。 |
Pattern.CASE_INSENSITIVE | 默認(rèn)情況下,大小寫不敏感的匹配只適用于US-ASCII字符集。這個(gè)標(biāo)志能讓表達(dá)式忽略大小寫進(jìn)行匹配。要想對(duì)Unicode字符進(jìn)行大小不明感的匹配,只要將UNICODE_CASE與這個(gè)標(biāo)志合起來(lái)就行了。 通過(guò)嵌入式標(biāo)志表達(dá)式(?i)也可以啟用不區(qū)分大小寫的匹配。 指定此標(biāo)志可能對(duì)性能產(chǎn)生一些影響。 |
Pattern.COMMENTS ??????????????? | 這種模式下,匹配時(shí)會(huì)忽略(正則表達(dá)式里的)空格字符(不是指表達(dá)式里的”//s”,而是指表達(dá)式里的空格,tab,回車之類)和注釋(從#開始,一直到這行結(jié)束)。 通過(guò)嵌入式標(biāo)志表達(dá)式(?x) 也可以啟用注釋模式。 |
Pattern.MULTILINE | 默認(rèn)情況下,輸入的字符串被看作是一行,即便是這一行中包好了換行符也被看作一行。當(dāng)匹配“^”到“$”之間的內(nèi)容的時(shí)候,整個(gè)輸入被看成一個(gè)一行。啟用多行模式之后,包含換行符的輸入將被自動(dòng)轉(zhuǎn)換成多行,然后進(jìn)行匹配。 通過(guò)嵌入式標(biāo)志表達(dá)式 (?m) 也可以啟用多行模式。 |
Pattern.LITERAL | 啟用字面值解析模式。 指定此標(biāo)志后,指定模式的輸入字符串就會(huì)作為字面值字符序列來(lái)對(duì)待。輸入序列中的元字符或轉(zhuǎn)義序列不具有任何特殊意義。 標(biāo)志 CASE_INSENSITIVE 和 UNICODE_CASE 在與此標(biāo)志一起使用時(shí)將對(duì)匹配產(chǎn)生影響。其他標(biāo)志都變得多余了。 不存在可以啟用字面值解析的嵌入式標(biāo)志字符。 |
Pattern.DOTALL | 在這種模式中,表達(dá)式 .可以匹配任何字符,包括行結(jié)束符。默認(rèn)情況下,此表達(dá)式不匹配行結(jié)束符。 通過(guò)嵌入式標(biāo)志表達(dá)式 (?s) 也可以啟用此種模式(s 是 “single-line” 模式的助記符,在 Perl 中也使用它)。 |
Pattern.UNICODE_CASE | 在這個(gè)模式下,如果你還啟用了CASE_INSENSITIVE標(biāo)志,那么它會(huì)對(duì)Unicode字符進(jìn)行大小寫不敏感的匹配。默認(rèn)情況下,大小寫不明感的匹配只適用于US-ASCII字符集。 指定此標(biāo)志可能對(duì)性能產(chǎn)生影響。 |
Pattern.CANON_EQ | 當(dāng)且僅當(dāng)兩個(gè)字符的正規(guī)分解(canonical decomposition)都完全相同的情況下,才認(rèn)定匹配。比如用了這個(gè)標(biāo)志之后,表達(dá)式a/u030A會(huì)匹配?。默認(rèn)情況下,不考慮規(guī)范相等性(canonical equivalence)。 指定此標(biāo)志可能對(duì)性能產(chǎn)生影響。 |
在這些標(biāo)志里面,Pattern.CASE_INSENSITIVE,Pattern.MULTILINE,以及Pattern.COMMENTS是最有用的(其中Pattern.COMMENTS還能幫我們把思路理清楚,并且/或者做文檔)。注意,你可以用在表達(dá)式里插記號(hào)的方式來(lái)啟用絕大多數(shù)的模式。這些記號(hào)就在上面那張表的各個(gè)標(biāo)志的下面。你希望模式從哪里開始啟動(dòng),就在哪里插記號(hào)。
可以用OR (|)運(yùn)算符把這些標(biāo)志配合使用。
代碼示例
多行模式:Pattern.MULTILINE 示例
我測(cè)試了一下,也就是說(shuō)如果沒(méi)有 MULTILINE 標(biāo)志的話, ^ 和 $ 只能匹配輸入序列的開始和結(jié)束;否則,就可以匹配輸入序列內(nèi)部的行結(jié)束符。測(cè)試代碼如下:
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("===========匹配字符串結(jié)尾(非多行模式)==========="); p = Pattern.compile("java$"); m = p.matcher(str); while (m.find()) { System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]"); } System.out.println("===========匹配字符串結(jié)尾(多行模式)==========="); p = Pattern.compile("java$", Pattern.MULTILINE); m = p.matcher(str); while (m.find()) { System.out.println(m.group() + " 位置:[" + m.start() + "," + m.end() + "]"); } } }
===========匹配字符串開頭(非多行模式)===========
hello 位置:[0,5]
===========匹配字符串開頭(多行模式)===========
hello 位置:[0,5]
hello 位置:[13,18]
hello 位置:[25,30]
===========匹配字符串結(jié)尾(非多行模式)===========
java 位置:[31,35]
===========匹配字符串結(jié)尾(多行模式)===========
java 位置:[19,23]
java 位置:[31,35]
忽略大小寫:Pattern.CASE_INSENSITIVE 示例
有的時(shí)候,需要進(jìn)行忽略大小寫的匹配。該例子實(shí)現(xiàn)匹配攝氏溫度和華氏溫度,對(duì)于以C、c、F和f結(jié)尾的溫度值都能匹配。
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("===========正則內(nèi)部忽略大小寫==========="); 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("===========內(nèi)部不忽略大小寫==========="); 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忽略大小寫===========
-3.33c true
-3.33C true
===========不忽略大小寫===========
-3.33c false
-3.33C true
===========正則內(nèi)部忽略大小寫===========
-3.33c true
-3.33C true
===========內(nèi)部不忽略大小寫===========
-3.33c false
-3.33C true
啟用注釋:Pattern.COMMENTS 示例
啟用注釋,開啟之后,正則表達(dá)式中的空格以及#號(hào)行將被忽略。
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啟用注釋===========
1234 true
===========不啟用注釋===========
1234 false
===========正則啟用注釋===========
1234 true
===========不啟用注釋===========
1234 false
可以看到,#號(hào)到行尾的注釋部分和前面的空白字符都被忽略了。正則表達(dá)式內(nèi)置的啟用注釋為(?x)。
啟用 dotall 模式:Pattern.DOTALL 示例
啟用dotall模式,一般情況下,點(diǎn)號(hào)(.)匹配任意字符,但不匹配換行符,啟用這個(gè)模式之后,點(diǎn)號(hào)還能匹配換行符。
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 示例
啟用這個(gè)模式之后,所有元字符、轉(zhuǎn)義字符都被看成普通的字符,不再具有其他意義。
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 } }
附:貪婪匹配與懶惰匹配
考慮這個(gè)表達(dá)式:a.*b,它將會(huì)匹配最長(zhǎng)的以a開始,以b結(jié)束的字符串。如果用它來(lái)搜索aabab的話,它會(huì)匹配整個(gè)字符串a(chǎn)abab。這被稱為貪婪匹配。
有時(shí),我們更需要懶惰匹配,也就是匹配盡可能少的字符。前面給出的限定符都可以被轉(zhuǎn)化為懶惰匹配模式,只要在它后面加上一個(gè)問(wèn)號(hào)?。這樣.*?就意味著匹配任意數(shù)量的重復(fù),但是在能使整個(gè)匹配成功的前提下使用最少的重復(fù)。
a.*?b匹配最短的,以a開始,以b結(jié)束的字符串。如果把它應(yīng)用于aabab的話,它會(huì)匹配aab和ab。
public static void main(String[] args) { String str = "北京市(海淀區(qū))(朝陽(yáng)區(qū))"; String paternStr = ".*(?=\\()"; Pattern pattern = Pattern.compile(paternStr); Matcher matcher = pattern.matcher(str); if (matcher.find()) { System.out.println(matcher.group(0)); } }
上述方法的輸出為:北京市(海淀區(qū))
public static void main(String[] args) { String str = "北京市(海淀區(qū))(朝陽(yáng)區(qū))"; String paternStr = ".*?(?=\\()"; Pattern pattern = Pattern.compile(paternStr); Matcher matcher = pattern.matcher(str); if (matcher.find()) { System.out.println(matcher.group(0)); } }
上述方法輸出:北京市
總結(jié)
到此這篇關(guān)于Java正則表達(dá)式之Pattern類的文章就介紹到這了,更多相關(guān)Java正則表達(dá)式Pattern類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis數(shù)據(jù)脫敏的實(shí)現(xiàn)方案介紹
在我們數(shù)據(jù)庫(kù)中有些時(shí)候會(huì)保存一些用戶的敏感信息,比如:手機(jī)號(hào)、銀行卡等信息,如果這些信息以明文的方式保存,那么是不安全的2022-08-08詳解Http請(qǐng)求中Content-Type講解以及在Spring MVC中的應(yīng)用
這篇文章主要介紹了Http請(qǐng)求中Content-Type講解以及在Spring MVC中的應(yīng)用的相關(guān)資料,需要的朋友可以參考下2017-02-02SpringBoot項(xiàng)目設(shè)置斷點(diǎn)debug調(diào)試無(wú)效忽略web.xml問(wèn)題的解決
這篇文章主要介紹了SpringBoot項(xiàng)目設(shè)置斷點(diǎn)debug調(diào)試無(wú)效忽略web.xml問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Spring Boot整合web層實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了Spring Boot整合web層實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04java calendar 日期實(shí)現(xiàn)不斷加一天的代碼
這篇文章主要介紹了java calendar 日期實(shí)現(xiàn)不斷加一天的代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10mybatis插件實(shí)現(xiàn)自定義改寫表名實(shí)例代碼
在數(shù)據(jù)庫(kù)操作過(guò)程中,經(jīng)常有修改表名的需求,下面這篇文章主要給大家介紹了關(guān)于mybatis插件實(shí)現(xiàn)自定義改寫表名的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04Mybatis實(shí)現(xiàn)自定義的typehandler三步曲
這篇文章主要介紹了Mybatis實(shí)現(xiàn)自定義的typehandler三步曲的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07淺談Arrays.asList() 和ArrayList類型區(qū)別
下面小編就為大家?guī)?lái)一篇Arrays.asList() 和ArrayList類型區(qū)別。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10