從 例子 開始 入門 正則 表示式(-)
正則 是個難啃的骨頭,以前看著會正則的人 感覺都好牛逼。於是工作了2年了終於鼓起勇氣啃這個骨頭了。。
例子入手
首先我們先看下相關的字元代表。我們先看這個例子。這個:chestnut:就是驗證字串是否是數字。
let regex = /^[0-9]+$/; let number = '123'; let string = 'abc'; regex.test(number); // true regex.test(string); // false 複製程式碼
可能很多人這時用到了百度谷歌一下然後複製過去直接用就OK了,但是這樣沉澱不到東西,所以我們來靜下心看看這個正則到底什麼意思,首先我們要了解的是相關的
- ^ :脫字元,匹配開頭,在多行匹配中匹配行開頭,有時也表示求反的概念。
- $ :美元符號, 匹配結尾,在多行匹配中匹配行結尾。
- {m,} 表示至少出現m次。
- {m} 等價於{m,m},表示出現m次。
- +: 等價於{1,},表示出現至少一次。記憶方式:加號是追加的意思,得先有一個,然後才考慮追加。
- *:等價於{0,},表示出現任意次,有可能不出現。記憶方式:看看天上的星星,可能一顆沒有,可能零散有幾顆,可能數也數不過來。
可能這時你有些不理解 [0-9],其實他等價於 [0123456789] ,在正則裡可以縮寫所以為 [0-9], 同理[a-z],[A-Z]也是同樣的道理。為什麼使用正則因為他書寫簡單,我們還可以簡化,讓我們等下看看接下來的這些字元,思考下怎麼繼續簡化。
那我們大概能猜到這個意思代表什麼了,從 開頭(^) 到 結尾($) 0-9([0-9]) 出現 至少一次 (+) , 所以就很好理解了,為什麼這個是驗證數字的想必就能理解了。
接下來我們再來看一些特殊字元:
- \d就是[0-9]。表示是一位數字。記憶方式:其英文是digit(數字)。
- \D就是[^0-9]。表示除數字外的任意字元。
- \w就是[0-9a-zA-Z_]。表示數字、大小寫字母和下劃線。記憶方式:w是word的簡寫,也稱單詞字元。
- \W是[^0-9a-zA-Z_]。非單詞字元。
- \s是[ \t\v\n\r\f]。表示空白符,包括空格、水平製表符、垂直製表符、換行符、回車符、換頁符。記憶方式:s是space character的首字母。
- \S是[^ \t\v\n\r\f]。 非空白符。
- .就是[^\n\r\u2028\u2029]。萬用字元,表示幾乎任意字元。換行符、回車符、行分隔符和段分隔符除外。記憶方式:想想省略號...中的每個點,都可以理解成佔位符,表示任何類似的東西。
好的我們看到了 \d 其實就是 [0-9],此時忽然恍然大悟,原來上面的正則還能簡化:
let regex = /^\d+$/; // /^[0-9]+$/; 複製程式碼
這時我們大概 已經懂得這個正則代表什麼東西了,之後再出現驗證使用者輸入的是不是數字,就別再百度了,分分鐘就寫出來。
舉一反三
我們已經瞭解之前的這個例子後,大概能推敲如何實現驗證全是字母:
let regex = /^[a-z]+$/; let string = 'abc'; let number = '123'; regex.test(number); //false regex.test(string);//true 複製程式碼
正則是區分大小寫字母的,所以,我們要驗證大寫字母的時大概是這樣:
let regex = /^[A-Z]+$/; let string = 'abc'; let STRING = 'ABC' let number = '123'; regex.test(number); //false regex.test(string);//false regex.test(STRING); //true 複製程式碼
好了我們已經反二了,接下來我們來反三,即是大寫字母又是小寫字母,怎麼去寫?
let regex = /^[a-zA-Z]+$/ 複製程式碼
估計到這裡我們都已經算入門了,不是很複雜的正則都可以自己去寫了。
考驗
接下來我們來看一些常用需求:
正則 驗證 手機 。
手機號碼是幾位,emmmm,等下我先數數 183 XXX XXX XX ,噗,11位,好吧當我沒說。那我們分析下,手機號, 首先全部都是數字, 開頭第一位一定是 數字 1 ,然後只要滿足 11位就可以了,我們已經把需求整理清楚了,如果我們用 js 去寫會怎麼寫?我這裡隨意寫一寫,可能有更好的方式
const isPhone = (number) => { //先判斷是不是字串 if (typeof number !== 'string' ||number.length !== 11 ) { return false; } const isNumber = (x) => isNaN(x*1); const mapData = (isFn, number) => { for( let i = 0;i < number.length; i+=1) { if(isFn(number.charAt(i))){ return false; break; } ; } return true; } const flag = mapData(isNumber, number) //判斷每一位是不是數字 if(!flag) { return false; } //判斷是不是1開頭。 if (number.indexOf('1') !== 0) { return false; } return true; } 複製程式碼
可見一個 js 書寫是多麼麻煩,也可能是我的解決方式不是很牛逼,隨便寫寫,各位有什麼好的解決方案也可以給我評論。。扯遠了。現在我們來看看要是用正則怎麼寫?
let regex= /^1\d{10}$/; 複製程式碼
一行程式碼搞定。就是這麼簡單,讓我們分析一下。
- ^ 開頭匹配
- 1 開頭沒毛病
- \d 表示 [0-9] 代表必須是數字
- {10} 也是 {10, 10} 表示 [0-9]出現10次,加上1 也就是說 11位。
- $ 結尾匹配沒毛病。 以上一行程式碼就搞定了。很簡便其實分析下也不是很難。
正則 驗證 郵箱 。
我就不寫什麼 js 的版本了,有興趣的同學可以自己嘗試寫寫。我們看看郵箱的正則應該是有這麼幾個需求的:
- ofollow,noindex">[email protected]
- @ 前需要有任意字元
- 郵箱 有 @ 符號。
- @後有任意字元
- 要有 .
- . 後跟任意字元
let regex = /^\w+@\w+\.\w+/; 複製程式碼
簡單分析一下:
- \w我們知道是[0-9a-zA-Z_]下劃線
- + 代表至少出現一次 好比 {1,}
- @ 必須需要。
- . 這裡要注意下,因為 . 是特殊正則字元, 代表萬用字元, 我們這裡需要的是 "." 字串,所以加了 \ 進行轉譯
補充案例
之前的例子們大概動了一些東西,讓我們再來看幾個例子。
匹配16進位制顏色值
大概是這樣:
#ffbbad #Fc01DF #FFF #ffE
寫法:
let regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g; 複製程式碼
分析:
開頭是#號,表示一個16進位制字元,可以用字元組[0-9a-fA-F]。然後 {6} 代表 出現6 次,這時候你可能有點迷 這個代表什麼 稍等引出這個 | 是分支的概念。再說說後面其實也很好理解 字元組[0-9a-fA-F] 出現3次。
- | 分支,其實可以理解為這個是程式設計中的或,很容易理解了。那麼,我們知道或者是惰性的,一個成立不向下執行,這裡其實也一樣。
讓我們再來一個案例:
驗證 匹配 yyyy-mm-dd : 2018-10-20
正則如下:
var regex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/; 複製程式碼
分析一波:
- 年 \d{4}[0-9]出現4次。
- 月 共12個月, 十位0的話就是 [1-9]月,十位1的話就是 [0-2]個月。
- 日 最多31天 ,十位0的話就是 [1-9]天,十位1,十位2就是[0-9]3的話只有0或者1。
結語。
正則是個大工程這裡只是一些簡單的正則,比如還有惰性匹配等 我們還沒有見到, 在後面的系列中我會慢慢的加入進去。未完...