精確匹配,也就是如出一轍java
System.out.println("t".matches("t")); // true
System.out.println("t*".matches("t\\*")); // true 注意對於通常字符串 *不是特殊字符 在正則中*是特殊字符,所以要表達其原本的意思須要使用轉義(此轉義時正則中的轉義,不是通常的轉義字符),即\*,可是\*並不是標準的轉義字符,所以使用\字符與*字符拼接標識轉義(此轉義時正則中的轉義,而不是通常字符串中的轉義),而表達字符則須要\\
System.out.println("$".matches("\\$")); // true
System.out.println("\t".matches("\t")); // false 正則匹配轉義字符,源字符串解析不解析爲轉義
System.out.println("\t".matches("\\t")); // true正則從左到右匹配,在正則中用到了對於\的轉義標識\字符串自己,這裏匹配時把普通字符串中的轉義字符視爲兩個字符,至關於精確匹配
System.out.println("\\t".matches("\\t")); // false
System.out.println("\\t".matches("\\\\t")); // true 正則表達式中匹配轉義,源字符串不匹配轉義
複製代碼
對於正常的字符串來講,除了普通字符和轉義字符以外,特殊字符有以下幾個git
\
做爲轉義字符的標識符,若是想不作爲標識符使用,而是單獨做爲字符串自己使用,必須使用\\
github
'
單引號,Java的字符,js的字符串,均可以使用單引號標識,所以爲了不混淆使用\'
標識單引號自己正則表達式
"
雙引號,多種語言的字符都使用雙引號標識,爲了不混淆使用\"
標識雙引號字符自己markdown
正則接受通常的轉義字符,也接受正則本身引入的所謂的轉義字符(提供正則功能)oop
\
與後邊的被轉譯字符視爲一個字符(事實上也確實如此),而對於正則本身引入的轉義字符,\
與後邊的被轉譯字符視爲兩個字符,只不過這種字符組合構成了轉義的功能
System.out.println("t*".matches("t\\*"));
\w \d
使用正則表達式引擎提供的特殊字符時務必注意不要與轉義字符混淆post
轉義字符的做用是讓一個特殊字符失去其自己的含義,而做爲一個普通的字符,對於普通字符來講即便使其具備特殊的含義性能
特殊字符以及其自己含有的特殊含義包括:學習
表示惟一匹配(匹配有限數量的字符)網站
. 匹配一個而且必須是1個的除了換行符以外的任意字符
\d
匹配一個數字
\D
除了數字以外的字符
\w
字母、數字、下劃線
\W
除了字母、數字、下劃線以外的字符
\s
空白字符(空格+製表符+換頁符+換行符)
\S
除了空白字符以外的其餘字符
指定範圍的匹配
[123]
枚舉匹配
[n-m1-2A-b]
指定範圍匹配(範圍的起始點與終止點都包含)(注意多範圍之間無空格)
使用^取非
注意僅在範圍匹配,也就是方括號內部使用^
作取非除了上述的特殊字符外,正則還提供了一些其餘的特殊字符,部分特殊字符與普通的轉義字符重複
重複匹配(匹配無限數量的字符)(通配符+集合區間)(重複匹配做爲修飾符放在惟一匹配的字符後邊)
匹配任意多個符合規則的字符
匹配至少一個
?
匹配0個或者1個
{n}
匹配n個{n,m}
匹配至少n個,至多m個,m省略表示至少含義,n設置爲0表示至多含義對於普通字符的轉義
正則表達式中須要進行轉義以表示字符自己的特殊字符
.
?
$
^
方括號
圓括號
大括號
|
\
\b
字符邊界(注意這個正則的特殊字符與普通轉義字符中有重複,在正則中顯然做爲字符邊界處理)
\B
標識非字符邊界
案例
String p = "The cat scattered his food all over the room.";
System.out.println(p.replaceAll("\\bcat\\b", "*")); // The * scattered his food all over the room.
複製代碼
適用於多行匹配的模式下對於字符串的匹配
^
標識字符串的開頭
是否使用^
邊界符號的區別在於,是不是針對整個字符串的匹配
"(T|t)he" => The car is parked in the garage. // 字符串中的兩個the都會被選中
"^(T|t)he" => The car is parked in the garage. // 只有字符串首部的The被選中,由於篩選的是以The或者the開頭的字符串
複製代碼
$
標識字符串的結尾
一樣的,是否使用$
邊界符號的區別在於,是不是針對整個字符串的匹配
"(at\.)" => The fat cat. sat. on the mat. // cat. sat. mat.都被選中
"(at\.)$" => The fat cat. sat. on the mat. // 只有最後一個mat.被選中
複製代碼
字符串邊界符號與正則模式的配合使用
在多行字符串的匹配中當只是用字符串邊界符號時,僅僅能匹配第一行或最後一行,由於有換行符的存在因此只能匹配一行
String p1 = String.join("\n", "I am scq000.", "I am scq000.");
// *
// I am scq000.
System.out.println(p1.replaceAll("^I am scq000\\.", "*"));
// I am scq000.
// *
System.out.println(p1.replaceAll("I am scq000\\.$", "*"));
// 多行沒法匹配
// I am scq000.
// I am scq000.
System.out.println(p1.replaceAll("^I am scq000\\.$", "*"));
複製代碼
多行匹配的引入
System.out.println(p1.replaceAll("(?m)^I am scq000\\.$", "*"));
複製代碼
(?m)
引入多行模式Pattern p = Pattern.compile("^I am scq000\\.$", Pattern.MULTILINE);
Matcher m = p.matcher(p1);
System.out.println(m.find());
複製代碼
Pattern p1 = Pattern.compile("^.*b.*$");
//輸出false,由於正則表達式中出現了^或$,默認只會匹配第一行,第二行的b匹配不到。
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("^.*b.*$",Pattern.MULTILINE);
//輸出true,指定了Pattern.MULTILINE模式,就能夠匹配多行了。
System.out.println(p2.matcher("a\nb").find());
複製代碼
"/.at(.)?$/" => The fat
cat sat
on the mat. 只有mat匹配
"/.at(.)?$/gm" => The fat
cat sat
on the mat. fat sat mat都匹配
複製代碼
m
多行模式
g
全局模式 匹配所有的符合規則的而不僅是第一個
i
忽略大小寫
指定模式的兩種方式:
在正則表達式中指定
String p1 = String.join("\n", "I Am scq000.", "I am scq000.");
// 結果爲:
// I Am scq000.
// *
// 可見第一行並未匹配
System.out.println(p1.replaceAll("I am scq000\\.", "*"));
// 多行模式 大小寫無關模式
// 結果爲:
// *
// *
// 可見所有都匹配
System.out.println(p1.replaceAll("(?mi)I am scq000\\.", "*"));
複製代碼
(?m)
(?i)
來標識正則模式,也可使用組合模式(?mi)
replaceAll
replaceFirst
在API參數中指定
Pattern p1 = Pattern.compile("^.*b.*$");
//輸出false,由於正則表達式中出現了^或$,默認只會匹配第一行,第二行的b匹配不到。
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("^.*b.*$",Pattern.MULTILINE);
//輸出true,指定了Pattern.MULTILINE模式,就能夠匹配多行了。
System.out.println(p2.matcher("a\nb").find());
複製代碼
Pattern解析正則時除了提供了多行模式外,還提供瞭如下幾種模式
DOTALL模式 用來解決正則表達式中的.
通配符不包含換行符帶來的問題
Pattern p1 = Pattern.compile("a.*b");
//輸出false,默認點(.)沒有匹配換行符
System.out.println(p1.matcher("a\nb").find());
Pattern p2 = Pattern.compile("a.*b", Pattern.DOTALL);
//輸出true,指定Pattern.DOTALL模式,能夠匹配換行符。
System.out.println(p2.matcher("a\nb").find());
複製代碼
UNIX_LINES
CASE_INSENSITIVE
LITERAL
UNICODE_CASE
CANON_EQ
UNICODE_CHARACTER_CLASS
同時使用多個模式的案例
Pattern p1 = Pattern.compile("^a.*b$");
//輸出false
System.out.println(p1.matcher("cc\na\nb").find());
Pattern p2 = Pattern.compile("^a.*b$", Pattern.DOTALL);
//輸出false,由於有^或&沒有匹配到下一行
System.out.println(p2.matcher("cc\na\nb").find());
Pattern p3 = Pattern.compile("^a.*b$", Pattern.MULTILINE);
//輸出false,匹配到下一行,但.沒有匹配換行符
System.out.println(p3.matcher("cc\na\nb").find());
//指定多個模式,中間用|隔開
Pattern p4 = Pattern.compile("^a.*b$", Pattern.DOTALL|Pattern.MULTILINE);
//輸出true
System.out.println(p4.matcher("cc\na\nb").find());
複製代碼
以上各個模式的用途可查看源碼註釋,每個模式都支持對應的正則表達式內嵌的標識方法,能夠參考其註釋
回溯引用是在分組的基礎之上使用的,指的是模式的後邊的部分引用前邊部分的已經匹配了的子表達式,使用回溯表達式有如下兩點好處
能夠寫出更加精簡高效的正則
\1
,\2
,....,其中\1
表示引用的第一個子表達式,\2
表示引用的第二個子表達式,以此類推。而\0
則表示整個表達式Hello what what is the first thing, and I am am scq000.
---\b(\w+)\s\1
可使用正則抽取分組信息
Pattern類配合Matchr類
String regex20 = "([0-9]{3,4})-([1-9]{7,8})";
Pattern pattern = Pattern.compile(regex20);
Matcher matcher = pattern.matcher("0312-2686815");
// 注意只有通過matches判斷後的matcher才能進行分組提取,不然會報錯No Match Fund
if (matcher.matches()) {
// 注意分組從1開始,序號爲0的分組是字符串總體
// 區號
System.out.println(matcher.group(1));
// 電話號
System.out.println(matcher.group(2));
// 匹配的總體
System.out.println(matcher.group(0));
} else {
System.out.println("不匹配");
}
// 去掉區號
System.out.println("0312-2686815".replaceAll(regex20, "$2"));
複製代碼
"str.matches"
方法內部使用的也是Pattern與Matchr,每一次調用方法都建立一個新的Patterm對象和一個新的Matcher對象,推薦直接定義一個Pattern來複用,以提高性能$1
而不是\1
,一樣注意$0
表明總體,$1
纔是第一個分組,以此類推若是要拒絕子正則表達式被引用,則在子正則的前邊加上?:
String regex20 = "(?:[0-9]{3,4})-([1-9]{7,8})";
// $0仍然是表示總體,$1由第二個子表達式補位,此時再引用$2 會報錯No Group 2
System.out.println("0312-2686815".replaceAll(regex20, "$2"));
複製代碼
由上邊的非捕獲正則?:
引出前向查找和後向查找(也能夠稱做零寬度斷言)----相對來講說比較難以理解
(?=regex)
"(T|t)he(?=\sfat)" => The fat cat sat on the mat.
匹配第一個The fat
(?!regex)
"(T|t)he(?!\sfat)" => The fat cat sat on the mat.
匹配第二個the(?<=regex)
"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.
匹配fat和mat(?<!regex)
"(?<!(T|t)he\s)(cat)" => The cat sat on cat.
匹配第二個cat|
或關係[^]
枚舉或指定範圍的匹配的取反!
負先發斷言,負後發斷言"/(.*at)/" => The fat cat sat on the mat.
整個字符串所有匹配?
便可:將?
加在重複匹配的修飾符(*
+
?
等)後邊便可"/(.*?at)/" => The fat cat sat on the mat.
at
前邊是任意數量的字符,惰性匹配就在這個任意數量的修飾符後加上?
標識儘量少匹配字符 所以只匹配The fat
123000
-> "(\\d+)(0*)"
-> "123000" ""
至少一個數字?我全都要123000
-> "(\\d+?)(0*)"
-> "123" "000"
至少一個數字?那就給你1個吧!可是考慮到後邊的只想要0,那就把0前邊的都給你0000
-> "(\\d+?)(0*)"
-> "0" "000"
至少一個數字,那就給你1個,其他的後邊的正好都要!哈哈9999
-> "(\\d??)(9*)"
-> "" "9999"
無關緊要,正好後邊都想要呢,那你就沒了~