前言
從給出的文本中,按照既定的相關規則,匹配出符合的數據,其中的規則就是正則表達式,使用正則表達式,可以使得我們用簡潔的代碼就能實現一定復雜的邏輯,比如判斷一個郵箱賬號是否符合正常的郵箱賬號,再比如判斷一個手機號是否正常的手機號,等等,正因為有了正則,得以讓文本處理起來更加的簡單。
當然,也并不是所有的場景我們都需要去使用正則,比如判斷兩個字符串是否相等,我們使用正則可以判斷如下:
private isEqual(a: string, b: string): boolean {const regExp = new RegExp(a)return regExp.test(b)}
直接傳遞兩個相比較的字符串即可。
const isEqual = this.isEqual("AbnerMing", "AbnerMing")console.log("===是否相等:" + isEqual)
顯然以上的判斷是比較冗余的,畢竟我們可以直接判斷。
const string1: string = "AbnerMing"const string2: string = "AbnerMing"console.log("===是否相等:" + (string1 === string2))
同樣的場景,比如包含,使用正則也是不如直接使用自帶的Api判斷方便。
正則判斷是否包含某一個字符串:
private isContains(a: string, b: string): boolean {const regExp = new RegExp(a, "g")return regExp.test(b)}
代碼判斷:
const string1: string = "我是AbnerMing,是一個程序員."const string2: string = "一個"const isContains = this.isContains(string2, string1)console.log("===是否包含:" + isContains)
針對字符串的包含判斷,我們也完全可以使用已有的方法進行判斷。
比如search方法:
const string1: string = "我是AbnerMing,是一個程序員."
const string2: string = "一個"
const isContains = string1.search(string2) != -1
console.log("===是否包含:" + isContains)
比如indexOf方法:
const string1: string = "我是AbnerMing,是一個程序員."
const string2: string = "一個"
const isContains = string1.indexOf(string2) != -1
console.log("===是否包含:" + isContains)
所以說,正則表達式固然很好,但是,在實際的開發中,我們也要針對性的選擇去用,讓它在該有的場景中發揮最大的作用。
了解正則及RegExp
在鴻蒙當中使用正則和TypeScript中如出一轍。
首先需要定義一個正則表達式。
const reg = new RegExp('正則表達式');
使用正則表達式
const res = reg.test('內容');
console.info('===結果:', res);
RegExp對象中,目前有兩個方法,一個是test方法,一個是exec方法。
test
此方法,返回一個Boolean,用來查找對應的字符串中是否存在,這個方法是使用最多的,常見的規則判斷一般都是使用它。
exec
此方法,用來查找并返回當前的匹配結果,并以數組的形式返回。
顯而易見,test方法可以判斷,是否符合正則表達式,可以用于判斷手機號,郵箱等等是否符合等等場景,而exec方法更側重于,查找相符合的數據。
常見元字符
元字符?是一個比較特殊的字符,也是一種特殊規則的文本,主要用于規定前導字符在目標對象中的出現模式,比如匹配數字,匹配字母等等匹配一定規則的文本,常見的元字符如下:
字符匹配
普通字符:直接按照給定的文本進行匹配,比如,一段文本中,匹配到字母“A”的字符。
元字符:元字符上面已經說了,它是具有特殊的含義,例如 \d 匹配任意數字字符,\w 匹配任意字母數字字符,. 匹配任意字符(除了換行符)等。
量詞
*:匹配前面的模式零次或多次
+:匹配前面的模式一次或多次
?:匹配前面的模式零次或一次
{n}:匹配前面的模式恰好 n 次
{n,}:匹配前面的模式至少 n 次
{n,m}:匹配前面的模式至少 n 次且不超過 m 次
字符類
[]:匹配括號內的任意一個字符。例如,[abc] 匹配字符 “a”、“b” 或 “c”
[^ ]:匹配除了括號內的字符以外的任意一個字符。例如,[^abc] 匹配除了字符 “a”、“b” 或 “c” 以外的任意字符
邊界匹配
^:匹配字符串的開頭
$:匹配字符串的結尾
\b:匹配單詞邊界
\B:匹配非單詞邊界
分組和捕獲
( ):用于分組和捕獲子表達式
(?: ):用于分組但不捕獲子表達式
特殊字符
\:轉義字符,用于匹配特殊字符本身
.:匹配任意字符(除了換行符)
|:用于指定多個模式的選擇
數字
數字:^[0-9]*$
n位的數字:^\d{n}$
至少n位的數字:^\d{n,}$
m-n位的數字:^\d{m,n}$
零和非零開頭的數字:^(0|[1-9][0-9]*)$
非零開頭的最多帶兩位小數的數字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
帶1-2位小數的正數或負數:^(-)?\d+(.\d{1,2})?$
正數、負數、和小數:^(-|+)?\d+(.\d+)?$
有兩位小數的正實數:^[0-9]+(.[0-9]{2})?$
有1~3位小數的正實數:^[0-9]+(.[0-9]{1,3})?$
非零的正整數:^[1-9]\d*$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]$
非零的負整數:^-[1-9][]0-9"$ 或 ^-[1-9]\d$
非負整數:^\d+$ 或 ^[1-9]\d*|0$
非正整數:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非負浮點數:^\d+(.\d+)?$ 或 1\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$
非正浮點數:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$
正浮點數:^[1-9]\d*.\d*|0.\d*[1-9]\d*$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
負浮點數:^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
浮點數:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$
校驗字符的表達式
漢字:^[\u4e00-\u9fa5]{0,}$
英文和數字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
長度為3-20的所有字符:^.{3,20}$
由26個英文字母組成的字符串:^[A-Za-z]+$
由26個大寫英文字母組成的字符串:^[A-Z]+$
由26個小寫英文字母組成的字符串:^[a-z]+$
由數字和26個英文字母組成的字符串:^[A-Za-z0-9]+$
由數字、26個英文字母或者下劃線組成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、數字包括下劃線:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、數字但不包括下劃線等符號:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以輸入含有^%&',;=?KaTeX parse error: Expected group after '^' at position 8: \"等字符:[^?%&',;=?\x22]+
禁止輸入含有的字符:[^\x22]+
特殊需求表達式
Email地址:^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
手機號碼(可根據目前國內收集號擴展前兩位開頭號碼):^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
電話號碼(“XXX-XXXXXXX”、“XXXX-XXXXXXXX”、“XXX-XXXXXXX”、“XXX-XXXXXXXX”、"XXXXXXX"和"XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$
國內電話號碼(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
15位身份證號:2\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$
18位身份證號:3\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):4[a-zA-Z0-9_]{4,15}$
密碼(以字母開頭,長度在6~18之間,只能包含字母、數字和下劃線):^[a-zA-Z]\w{5,17}$
強密碼(必須包含大小寫字母和數字的組合,不能使用特殊字符,長度在8-10之間):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$,例如:2014-10-12
^[1-9]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\s+(20|21|22|23|[0-1]\d):[0-5]\d:[0-5]\d$,例如:2014-10-12 12:20:00
一年的12個月(01~09和1~12):^(0?[1-9]|1[0-2])$
一個月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
錢的輸入格式:
有四種錢的表示形式我們可以接受:“10000.00” 和 “10,000.00”, 和沒有 “分” 的 “10000” 和 “10,000”:^[1-9][0-9]*$
這表示任意一個不以0開頭的數字,但是,這也意味著一個字符"0"不通過,所以我們采用下面的形式:^(0|[1-9][0-9]*)$
一個0或者一個不以0開頭的數字.我們還可以允許開頭有一個負號:^(0|-?[1-9][0-9]*)$
這表示一個0或者一個可能為負的開頭不為0的數字.讓用戶以0開頭好了.把負號的也去掉,因為錢總不能是負的吧.下面我們要加的是說明可能的小數部分:^[0-9]+(.[0-9]+)?$
必須說明的是,小數點后面至少應該有1位數,所以"10."是不通過的,但是 “10” 和 “10.2” 是通過的:^[0-9]+(.[0-9]{2})?$
這樣我們規定小數點后面必須有兩位,如果你認為太苛刻了,可以這樣:^[0-9]+(.[0-9]{1,2})?$
這樣就允許用戶只寫一位小數.下面我們該考慮數字中的逗號了,我們可以這樣:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
1到3個數字,后面跟著任意個 逗號+3個數字,逗號成為可選,而不是必須:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
xml文件:^([a-zA-Z]±?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
中文字符的正則表達式:[\u4e00-\u9fa5]
雙字節字符:[^\x00-\xff] (包括漢字在內,可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1))
空白行的正則表達式:\n\s*\r (可以用來刪除空白行)
HTML標記的正則表達式:<(\S*?)[^>]>.?</\1>|<.*? />
騰訊QQ號:[1-9][0-9]{4,} (騰訊QQ號從10000開始)
中國郵政編碼:[1-9]\d{5}(?!\d) (中國郵政編碼為6位數字)
IP地址:\d+.\d+.\d+.\d+ (提取IP地址時有用)
IP地址:((?😦?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))
正確使用正則
應用代碼
let regex: RegExp = /\s*/g;
建議改法
let regexp: RegExp = new RegExp('\\s*','g');
原因
如果正則表達式中使用了標志符,需要將其作為new RegExp()的參數。
簡單舉例
上面的元字符中,已經給出了大量的匹配規則,大家直接套用即可,比如判斷是否是一個郵箱,代碼如下:
private isEmail(txt: string): boolean {const regExp = new RegExp('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')return regExp.test(txt)}
相關總結
合理的使用正則表達式,確實在實際的開發中能給我們帶來一定的便利,特別是在一些復雜的匹配時,能夠帶來高效的查找,也能夠提高我們的開發效率,但在處理極度復雜任務時可能需要結合其他工具。
在開發中,對于輸入的規則是否是RegExp類型,我們可以通過系統提供的isRegExp來進行判斷,代碼如下:
let type = new util.types()
let result = type.isRegExp(new RegExp('abc'))
console.info("=== " + result);