一、瞭解正則表達式
1.1 什麼是正則表達式?
正則表達式,又稱規則表達式。正則表達式是對字符 串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。通常被用來檢索、替換那些符合某個模式(規則)的文本。在Java Web中用於前端校驗的字符串限制。
1.2 正則表達式的特點
- 靈活性、邏輯性和功能性非常強
- 可以迅速地用極簡單的方式達到字符串的複雜控制
- 對於剛接觸的人來說,比較晦澀難懂
1.3 正則表達式的語法
1.3.1 簡單的語法使用
複雜版:var patt=new RegExp(pattern,modifiers);
簡單版:var patt=/pattern/modifiers;
1.3.2 語法規範
正則表達式(regular expression)描述了一種字符串匹配的模式(pattern),可以用來檢查一個串是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串等。
普通字符
普通字符包括沒有顯式指定爲元字符的所有可打印和不可打印字符。這包括所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號。
非打印字符
非打印字符也可以是正則表達式的組成部分。下表列出了表示非打印字符的轉義序列
非打印字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須爲 A-Z 或 a-z 之一。否則,將 c 視爲一個原義的 ‘c’ 字符。 |
\f | 匹配一個換頁符。等價於 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價於 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價於 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。注意 Unicode 正則表達式會匹配全角空格符。 |
\S | 匹配任何非空白字符。等價於[^ \f\n\r\t\v] |
\t | 匹配一個製表符。等價於 \x09 和 \cI。 |
\v | 匹配一個垂直製表符。等價於 \x0b 和 \cK。 |
特殊字符
所謂特殊字符,就是一些有特殊含義的字符,如上面說的 runoo*b 中的 *****,簡單的說就是表示任何字符串的意思。如果要查找字符串中的 ***** 符號,則需要對 ***** 進行轉義,即在其前加一個 \: runo*ob 匹配 runo*ob。
許多元字符要求在試圖匹配它們時特別對待。若要匹配這些特殊字符,必須首先使字符"轉義",即,將反斜槓字符 \ 放在它們前面。下表列出了正則表達式中的特殊字符
特別字符 | 描述 |
---|---|
$ | 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,請使用 $。 |
( ) | 標記一個子表達式的開始和結束位置。子表達式可以獲取供以後使用。要匹配這些字符,請使用 ( 和 )。 |
* | 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 *。 |
+ | 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 +。 |
. | 匹配除換行符 \n 之外的任何單字符。要匹配 . ,請使用 . 。 |
[ | 標記一箇中括號表達式的開始。要匹配 [,請使用 [。 |
? | 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 ?。 |
\ | 將下一個字符標記爲或特殊字符、或原義字符、或向後引用、或八進制轉義符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配換行符。序列 ‘\’ 匹配 “”,而 ‘(’ 則匹配 “(”。 |
^ | 匹配輸入字符串的開始位置,除非在方括號表達式中使用,當該符號在方括號表達式中使用時,表示不接受該方括號表達式中的字符集合。要匹配 ^ 字符本身,請使用 ^。 |
{ | 標記限定符表達式的開始。要匹配 {,請使用 {。 |
| | 指明兩項之間的一個選擇。要匹配 | ,請使用 \ |
限定符
限定符用來指定正則表達式的一個給定組件必須要出現多少次才能滿足匹配。有 ***** 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6種。正則表達式的限定符有:
字符 | 描述 |
---|---|
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等價於{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等價於 {1,}。 |
? | 匹配前面的子表達式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等價於 {0,1}。 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的兩個 o。 |
{n,} | n 是一個非負整數。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等價於 ‘o+’。‘o{0,}’ 則等價於 ‘o*’。 |
{n,m} | m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 將匹配 “fooooood” 中的前三個 o。‘o{0,1}’ 等價於 ‘o?’。請注意在逗號和兩個數之間不能有空格。 |
二、正則表達式的修飾符
修飾符用於執行區分大小寫和全局匹配
修飾符 | 描述 |
---|---|
i | 執行對大小寫不敏感的匹配。 |
g | 執行全局匹配(查找所有匹配而非在找到第一個匹配後停止)。 |
m | 執行多行匹配。 |
// 默認會區分大小寫
var reg = /hello/
var flag = reg.test("Hello World")
console.log(flag) // false
// 添加i修飾符 不區分大小寫
var reg2 = /hello/i
var flag2 = reg2.test("Hello World")
console.log(flag2) // true
var str = "I'm in a bad mood,really bad"
// 默認非全局匹配
var reg3 = /bad/
var newStr = str.replace(reg3,"good")
// 只替換了一個bad
console.log(newStr) // I'm in a good mood,really bad
// 全局匹配
var reg4 = /bad/g
var newStr2 = str.replace(reg4,"good")
// 替換了全局的bad爲good
console.log(newStr2) // I'm in a good mood,really good
// 同時使用
var reg5 = /bad/gi
var newStr3 = reg5.test("i am a BaD");
console.log(newStr3);
三、正則表達式的多種修飾類
以下帶有[]{}的都是正則表達式,[]內代表是對字符串的限制,而{}是代表長度。如果沒有書寫{}則默認長度爲1
matches方法爲正則表達式匹配方法,判斷字符串是否滿足正則表達式的校驗(後面也會講到)
3.1 字符類
字符類用於查找某個範圍內的字符
表達式 | 描述 |
---|---|
[abc] | 查找方括號之間的任何字符。 |
[^abc] | 查找任何不在方括號之間的字符。 |
[0-9] | 查找任何從 0 至 9 的數字。 |
[a-z] | 查找任何從小寫 a 到小寫 z 的字符。 |
[A-Z] | 查找任何從大寫 A 到大寫 Z 的字符。 |
[A-z] | 查找任何從大寫 A 到小寫 z 的字符。 |
[abcd] | 查找給定集合內的任何字符。 |
[^abcd] | 查找給定集合外的任何字符。 |
(red|blue|green) | 查找任何指定的選項。 |
// [abc] a、b 或 c(簡單類)
String reg1 = "[abc]";
System.out.println("a".matches(reg1)); // true
// [^abc] 任何字符,除了 a、b 或 c(否定)
String reg2 = "[^abc]";
System.out.println("d".matches(reg2)); // true
// [a-zA-Z] a 到 z 或 A 到 Z,兩頭的字母包括在內(範圍)
String reg3 = "[a-zA-Z]";
System.out.println("ab".matches(reg3)); // false
// [0-9] 0到9的字符都包括
String reg4 = "[0-9]";
System.out.println("0".matches(reg4)); // true
// 需求:有一個字符,可以是a-z,也可以是A-Z,也可以是0-9,也可以是?
String reg5 = "[a-zA-Z0-9?]";
System.out.println("!".matches(reg5)); // false
3.2 元字符
元字符(Metacharacter)是擁有特殊含義的字符(注意:在使用的時候需要\\W,因爲一個\默認爲轉義字符)
元字符 | 描述 |
---|---|
. | 查找單個字符,除了換行和行結束符。 |
\w | 查找單詞字符。 |
\W | 查找非單詞字符。 |
\d | 查找數字。 |
\D | 查找非數字字符。 |
\s | 查找空白字符。 |
\S | 查找非空白字符。 |
// . 任何字符。
String reg1 = ".";
System.out.println(">".matches(reg1)); // true
System.out.println(">a".matches(reg1)); // false
// \d 數字:[0-9]
String reg2 = "\\d";
System.out.println("11".matches(reg2)); // false
// \D 非數字:[^0-9]
String reg3 = "[^0-9]";
System.out.println("a".matches(reg3)); // true
System.out.println("11".matches(reg3)); // false
String reg4 = "\\D";
System.out.println("1".matches(reg4)); // false
// \w 單詞字符:[a-zA-Z_0-9]
String reg5 = "\\w";
System.out.println("_".matches(reg5)); // true
String reg6 = "[a-zA-Z0-9_]";
System.out.println("_".matches(reg6)); // true
// \W 非單詞字符:[^\w]
String reg7 = "[^a-zA-Z0-9_]";
System.out.println("a".matches(reg7)); // false
String reg8 = "[^\\w]";
System.out.println("!".matches(reg8)); // true
String reg9 = "[\\W]";
System.out.println("!".matches(reg9)); // true
// \s 空白字符:[ \t\n\x0B\f\r]
String reg10 = "\\s";
System.out.println(" ".matches(reg10)); // true
// \S 非空白字符:[^\s]
String reg11 = "\\S";
System.out.println("!".matches(reg11)); // true
3.3 匹配正則後的默認字符串
在使用以下四種正則表達式matches方法匹配字符串時,以下四種正則表達式表示的意義均是相同的!
- String reg1 = “abc”;
- 當reg1在使用matches進行對字符串的正則校驗時,它已經不是一個普通的字符串了,"abc"隱式的存在[]和{},也就是等價於我們的第三種,爲每一個字符添加了一個[]和{}
- String reg2 = [a][b][c];
- reg2正則表達式隱式存在{1}的長度,所以也是等於於我們的第三種
- String reg3 = [a]{1}[b]{1}[c]{1};
- reg3正則表達式是沒有省略任何內容的正則表達式
- String reg4 = [abc]{3}
- reg4正則表達式可以解釋爲:在abc三個字符中,必須滿足它的3個長度,也就是正則校驗時規定字符串必須是abc
注意: 第一種看起來是一個字符串,當調用了matches方法進行字符串的正則校驗時,該字符串搖身一變就成爲了一個特殊的正則表達式!
3.4 數量詞
量詞 | 描述 |
---|---|
n+ | 匹配任何包含至少一個 n 的字符串。例如,/a+/ 匹配 “candy” 中的 “a”,“caaaaaaandy” 中所有的 “a”。 |
n* | 匹配任何包含零個或多個 n 的字符串。例如,/bo*/ 匹配 “A ghost booooed” 中的 “boooo”,“A bird warbled” 中的 “b”,但是不匹配 “A goat grunted”。 |
n? | 匹配任何包含零個或一個 n 的字符串。例如,/e?le?/ 匹配 “angel” 中的 “el”,“angle” 中的 “le”。 |
n{X} | 匹配包含 X 個 n 的序列的字符串。例如,/a{2}/ 不匹配 “candy,” 中的 “a”,但是匹配 “caandy,” 中的兩個 “a”,且匹配 “caaandy.” 中的前兩個 “a”。 |
n{X,} | X 是一個正整數。前面的模式 n 連續出現至少 X 次時匹配。例如,/a{2,}/ 不匹配 “candy” 中的 “a”,但是匹配 “caandy” 和 “caaaaaaandy.” 中所有的 “a”。 |
n{X,Y} | X 和 Y 爲正整數。前面的模式 n 連續出現至少 X 次,至多 Y 次時匹配。例如,/a{1,3}/ 不匹配 “cndy”,匹配 “candy,” 中的 “a”,“caandy,” 中的兩個 “a”,匹配 “caaaaaaandy” 中的前面三個 “a”。注意,當匹配 “caaaaaaandy” 時,即使原始字符串擁有更多的 “a”,匹配項也是 “aaa”。 |
n$ | 匹配任何結尾爲 n 的字符串。 |
^n | 匹配任何開頭爲 n 的字符串。 |
?=n | 匹配任何其後緊接指定字符串 n 的字符串。 |
?!n | 匹配任何其後沒有緊接指定字符串 n 的字符串。 |
// X? :X,一次或一次也沒有
String reg1 = "[a]?"; // 要麼是“a”要麼什麼都沒有
System.out.println("aaa".matches(reg1)); // false
// X* :X,零次到多次
String reg2 = "[a]*";
System.out.println("b".matches(reg2)); // false
// X+ :X,一次到 多次
String reg3 = "[a]+";
System.out.println("".matches(reg3)); // false
// X{n} :X,恰好 n 次
String reg4 = "[ab]{3}"; // 內容由a或b組成,長度爲3
System.out.println("aaa".matches(reg4)); // true
// X{n,} :X,至少 n 次
// 0次到多次
String reg5 = "[abc]{0,}"; // 內容由a組成,0次到多次!
System.out.println("aaaa".matches(reg5)); // true
// 1次到多次
String reg6 = "[a]{1,}";
System.out.println("".matches(reg6)); // false
// X{n,m} :X,至少 n 次,但是不超過 m 次
String reg7 = "[abc]{2,3}";
System.out.println("abca".matches(reg7)); // false
System.out.println("abc".matches(reg7)); // true
3.5 正則表達式的字符串方法
方法 | 描述 |
---|---|
search | 檢索與正則表達式相匹配的值。 |
match | 找到一個或多個正則表達式的匹配。 |
replace | 替換與正則表達式匹配的子串。 |
split | 把字符串分割爲字符串數組。 |
字符串分割示例(如下分割每一個打印內容都是都是相同的即爲a b c d)
// "a,b,c,d"
String str1 = "a,b,c,d";
String reg1 = "[,]{1}";
String[] strs1 = str1.split(reg1);
for (String str : strs1) {
System.out.println(str);
}
System.out.println("-----------");
// "a,,b,,c,,d"
String str2 = "a,,b,,c,,d";
// String reg2 = ",,";
String reg2 = "[,]{2}";
String[] strs2 = str2.split(reg2);
for (String str : strs2) {
System.out.println(str);
}
System.out.println("-----------");
// "a,b,,c,,,d"
String str3 = "a,b,,c,,,d";
String reg3 = "[,]{1,3}";
String[] strs3 = str3.split(reg3);
for (String str : strs3) {
System.out.println(str);
}
System.out.println("-----------");
// "a,,,,,,,,,b,,,,,,,,,c,,,,,d"
String str4 = "a,,,,,,,,,b,,,,,,,,,c,d";
String reg4 = "[,]+";
String[] strs4 = str4.split(reg4);
for (String str : strs4) {
System.out.println(str);
}
Java Script示例
<script>
var str = "hi66morning77"
// 匹配連續的2個數字 非全局匹配
var reg = /\d{2}/
console.log(str.match(reg)[0]) // 66
// 匹配連續的2個數字 全局匹配(推薦)
var reg2 = /\d{2}/g
console.log(str.match(reg2)) // ["66", "77"]
var str = "hi66morning77"
// 匹配連續的2個數字 非全局匹配
var reg = /\d{2}/
console.log(str.search(reg)) // 2
// 匹配a,b,m中的一個
var reg2 = /[abm]/
console.log(str.search(reg2)) // 4
</script>
3.6 正則表達式的對象
( Pattern和Matcher)模式和匹配器的典型調用順序如下:
//正則表達式
String reg = "[a]{3}";
//正則表達式 轉換爲 正則對象
Pattern pattern = Pattern.compile(reg);
//匹配字符串,匹配對象
Matcher matcher = pattern.matcher("aaa");
//開始匹配
boolean flag = matcher.matches();
System.out.println(flag);
3.7 正則表達式校驗手機號
需求:把一個字符串中的手機號碼獲取出來
要求:
- 手機號碼共11位
- 開頭第一位必須是1
- 第二位必須是356789的其中一位
- 其他9爲均爲數字(數字的範圍即是0~9)
/**
* 手機號碼
* 手機號碼共11位
* 開頭第一位必須是1
* 第二位必須是356789的其中一位
* 其他9爲均爲數字(數字的範圍即是0~9)
*/
String str = "18627775385...fadsfds18627775383..dsfjdsa18627775384";
String reg = "[1]{1}[356789]{1}\\d{9}";
//獲取正則對象
Pattern pattern = Pattern.compile(reg);
//獲取匹配對象
Matcher matcher = pattern.matcher(str);
//開始查找手機號
//find:在str中找子字符串,子字符串要和正則匹配
List<String> phones = new ArrayList<>();
while (matcher.find()) {
//找到了手機號,獲取手機號
String phone = matcher.group();
phones.add(phone);
}
/**
* 遍歷打印獲取到的手機號碼
*/
for (String phone : phones) {
System.out.println(phone);
}
3.8 正則表達式的RegExp對象方法
方法 | 描述 |
---|---|
exec | 檢索字符串中指定的值。返回找到的值,並確定其位置。沒有發現匹配,則返回 null。 |
test | 檢索字符串中指定的值。返回 true 或 false。 |
var patt1 = new RegExp("e");
document.write(patt1.test("The best things in life are free"));
//由於該字符串中存在字母 "e",以上代碼的輸出將是:true
var patt1 = new RegExp("e");
document.write(patt1.exec("The best things in life are free"));
//由於該字符串中存在字母 "e",以上代碼的輸出將是:e
四、正則表達式的使用
4.1 正則表達式的簡單使用
User實體類+校驗
package com.mylifes1110.java.userdemo;
/**
* User實體類+校驗
*
* 創建一個User對象,有賬號、密碼、郵箱
* 賬號:數字和字母組成;第一位必須是大寫字母;長度範圍6~10
* 密碼:由數字、字母和_組成;第一位必須是字母;長度爲6
* 郵箱:由qq號碼、@和.組成;必須是qq郵箱
*/
public class User {
private String username;
private String password;
private String email;
public User() {}
public User(String username, String password, String email) {
if (validateUsername(username)) {
this.username = username;
} else {
throw new MyIllegalArgumentsException("賬號輸入錯誤!");
}
if (validatePassword(password)) {
this.password = password;
} else {
throw new MyIllegalArgumentsException("密碼輸入錯誤!");
}
if (validateEmail(email)) {
this.email = email;
} else {
throw new MyIllegalArgumentsException("郵箱輸入錯誤!");
}
}
@Override
public String toString() {
return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\''
+ '}';
}
/**
* 校驗郵箱
* 郵箱:由qq號碼、@和.組成;必須是qq郵箱(QQ號碼位數是由5位到11位並且沒有0開頭的QQ號碼)
*/
private boolean validateEmail(String email) {
String reg = "[1-9]{5,11}@qq\\.com";
boolean matches = email.matches(reg);
return matches;
}
/**
* 校驗密碼
* 密碼:由數字、字母和_組成;第一位必須是字母;長度爲6
*/
private boolean validatePassword(String password) {
String reg = "[a-zA-Z]\\w{5}";
boolean matches = password.matches(reg);
return matches;
}
/**
* 校驗賬號
* 賬號:數字和字母組成;第一位必須是大寫字母;長度範圍6~10
*/
private boolean validateUsername(String username) {
String reg = "[A-Z][a-zA-Z0-9]{5,9}";
boolean matches = username.matches(reg);
return matches;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
if (validateEmail(email)) {
this.email = email;
} else {
throw new MyIllegalArgumentsException("郵箱輸入錯誤!");
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if (validatePassword(password)) {
this.password = password;
} else {
throw new MyIllegalArgumentsException("密碼輸入錯誤!");
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
if (validateUsername(username)) {
this.username = username;
} else {
throw new MyIllegalArgumentsException("賬號輸入錯誤!");
}
}
}
測試類
package com.mylifes1110.java.userdemo;
import java.util.Scanner;
/**
* 創建一個User對象,有賬號、密碼、郵箱
* 賬號:數字和字母組成;第一位必須是大寫字母;長度範圍6~10
* 密碼:由數字、字母和_組成;第一位必須是字母;長度爲6
* 郵箱:由qq號碼、@和.組成;必須是qq郵箱
*/
public class UserTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
User user = new User();
System.out.print("請輸入賬號:");
String username = sc.nextLine();
System.out.print("請輸入密碼:");
String password = sc.nextLine();
System.out.print("請輸入郵箱:");
String email = sc.nextLine();
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
System.out.println(user);
}
}
自定義異常類
package com.mylifes1110.java.userdemo;
public class MyIllegalArgumentsException extends RuntimeException {
public MyIllegalArgumentsException() {
}
public MyIllegalArgumentsException(String message) {
super(message);
}
public MyIllegalArgumentsException(String message, Throwable cause) {
super(message, cause);
}
public MyIllegalArgumentsException(Throwable cause) {
super(cause);
}
public MyIllegalArgumentsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
4.2 JavaScript中正則表達式常用校驗
匹配手機號
var reg = /^1\d{10}$/;
匹配QQ號
var reg = /^[1-9]\d{4,10}$/;
匹配身份證號
var reg = /^[1-9]\d{16}[Xx\d]$/;
變量名檢測(只能由字母,數字,下劃線組成,且不能以數字開頭,長度6-15)
var reg = /^[A-z_]\w{5,14}$/;
判斷是否爲郵箱email
驗證規則: 電子郵箱的正確寫法一般爲: 用戶名@郵箱網站.com(.cn)
第一部分:由字母、數字、下劃線、短線“-”組成
第二部分:爲一個域名,域名由字母、數字、短線“-”、域名後綴組成(域名後綴一般爲兩位到三位。例如:com cn net現在域名有的也會大於四位)
function isEmail(str){
var reg =/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;
return reg.test(str);
}