javascript
判断字符串 正则_(重学前端 - JavaScript(模块一)) 14、引用类型之 RegExp (正则)(详述)...
上一篇文章介紹了 JavaScript 中的 Date 類型,從地理方面的原理知識開始入手,如果大家認真看過上一篇文章,相信 JavaScript 中的 Date 類型已經難不住大家了!!! 但是今天要介紹的內容不僅在 JavaScript 中有著舉足輕重的地位,在其他語言中也是重中之重的存在,并且尤其是在字符串的模式匹配領域,沒錯就是你心中所想的正則表達式,只不過在 JavaScript 中使用正則表達式有著它自己獨特的地方,所以不得不單提出來加以介紹,如果你是一名前端人但是對于正則方面沒有系統的知識結構,或者說你從來都沒有使用過它,那么相信本篇文章對您而言會是一大助力!!!
一、什么是正則?
正則表達式是對字符串操作的一種邏輯公式,用事先定義好的字符或者這些特定字符的組合組成一個規則字符串,這種規則字符串用來表達對字符串的一種過濾邏輯。說的通俗一點,就是事先有一些特殊的字符被賦予了特殊的意義,我們可以用這些字符組合出不同的模式,去匹配符合該模式的字符串,這些字符叫做 元字符 。
目的 :
-1). 確定給定字符串是否符合正則表達式的過濾邏輯。
-2). 可以從字符串中獲取我們想要的部分。
特點 :
-1). 初學比較晦澀難懂。
-2). 靈活性、邏輯性、功能性較強。
-3). 可以迅速用極簡單的方式達到字符串的復雜控制。
那到底什么式正則表達式呢 ?
舉個栗子 :
/^[a-z0-9]+@[a-z0-9]+.(?:com.cn|(?:com|cn))$/
上面這個我們看到的就是類似 火星文 的東東就是正則表達式,只不過這時一個匹配郵箱的正則表達式,不信 ? 驗證之 ->
var reg = /^[0-9a-z]+@[0-9a-z]+.(?:com.cn|(?:com|cn))$/;// 網易 E-Mail :var str_wy = '17803218829@163.com';// QQ E-Mailvar str_qq = 'pgsyj@qq.com';// Google E-Mailvar str_google = 'pgsyj@gmail.com';// yahoo E-Mailvar str_yahoo = 'pgsyj@yahoo.com.cn';// sina E-mailvar str_sina = 'pgsyj@sina.cn';var arr = [str_wy, str_qq, str_google, str_yahoo, str_sina];console.log(arr.every((item) => reg.test(item)));// true二、為什么使用正則?
-1). 使用正則會使得匹配字符串變得更加簡單、快捷。
-2). 使用正則表達式可以給你增添一種捉摸不透的氣質。
-3).可以使用正則表達式可以隨意切換匹配的模式比較靈活多變,適合處理復雜的字符操作任務。
為什么必須用這個 ? 用原生的其他方法或者手段也可以呀 ?
舉個栗子 :
現在有一個字符串 apple123pear456banana789 如果不使用正則表達式你可以怎么將所有的數字取出呢 ?
(1). ES5 之前的做法 :
var str = 'apple123pear456banana789';var str_arr = str.split('');var arr = [];for(var i = 0; i < str_arr.length; i++) {if(!isNaN(Number(str_arr[i]))) {arr.push(str_arr[i]);}}console.log(arr);// [ '1', '2', '3', '4', '5', '6', '7', '8', '9' ](2). ES6 之后做法 :
var str = 'apple123pear456banana789';var str_arr = [...str];var arr = str_arr.filter((item, index) => !isNaN(Number(item)));console.log(arr);// [ '1', '2', '3', '4', '5', '6', '7', '8', '9' ](3). 正則表達式 :
var str = 'apple123pear456banana789';var reg = /d+/g;var arr = [...str.match(reg).toString().replace(/,/g, '')];console.log(arr);// [ '1', '2', '3', '4', '5', '6', '7', '8', '9' ]由上面這個示例可知,綜合比較三種方式,其實還是使用正則表達式這個方式更加顯得信手拈來,并且處理起來速度也更快。
所以在處理復雜的字符串操作或者數據校驗的時候必須使用正則表達式往往會取得意想不到的效果!
三、在 JavaScript 中正則的用法
-1). 創建正則表達式 :
(1). 構造函數式 :
var reg = new RegExp('[bc]at', 'ig');console.log(reg);// /[bc]at/gi(2). 字面量式 :
var reg = /[bc]at/ig;console.log(reg);// /[bc]at/gi其實構造器式的第一個參數還可以是一個字面量式的正則對象,盡管這樣做并沒有一個實際性的意義。但是卻可以修改其后面的行為標識符。
var reg = new RegExp(/[bc]at/i, 'ig');console.log(reg);// /[bc]at/gi這樣就成功的將字面量上的行為修飾符 i ,替換為了 gi 。
-2). RegExp 實例屬性 :
(1). global 屬性,判斷當前的正則表達式的實例是否有全局行為修飾符 g 。
(2). ignoreCase 屬性,判斷當前的正則表達式的實例是否有忽略大小寫的行為修飾符 i 。
(3). multiline 屬性,判斷當前的額正則表達式實例是否有匹配多行的行為修飾符 m 。
(4). lastIndex 屬性,下一次匹配的起始位置的索引。
(5). flags 屬性,獲取當前的行為修飾符。
(6). source 屬性,獲取正則表達式的字符串表現形式,但是會忽略行為修飾符 (i、m、g)。
var reg = /[a-z]{3}/img;var str = '123asD456def ghi789';console.log(reg.exec(str));// [ 'asD', index: 3, input: '123asD456def ghi789' ]console.log(`reg's g: ${reg.global}`);// reg's g: trueconsole.log(`reg's i: ${reg.ignoreCase}`);// reg's i: trueconsole.log(`reg's m: ${reg.multiline}`);// reg's m: trueconsole.log(`reg's lastIndex: ${reg.lastIndex}`);// reg's lastIndex: 6console.log(`reg's source: ${reg.source}`);-3). RegExp 的實例方法 :
(1). exec 方法 : 查找與正則表達式匹配的字符串,并將匹配的結果放入數組中并返回,返回結果數組。
(2). test 方法 : 查找字符串中是否有與正則表達式匹配的部分,返回布爾值
var reg = /d+/;var str = 'asd123def456';console.log(reg.test(str));// trueconsole.log(reg.exec(str));// [ '123', index: 3, input: 'asd123def456' ]=> 但是需要注意的是 exec() 方法 返回的結果數組有著 2 個屬性 :
A. index 屬性 : 匹配到字符串的起始位置
B. input 屬性 : 最近匹配的字符串
var reg = /d+/;var str = 'asd123def456';var res = reg.exec(str);console.log(`index: ${res.index}`);// index: 3console.log(`input: ${res.input}`);// input: asd123def456該案例中 1 在索引為 3 處,所以 index 會返回 3 。最近匹配的字符串是 asd123def456 所以會返回 asd123def456。
=> 但是你在使用 exec() 方法 的時候一定注意到過一個現象,就是一次只返回一個結果。如果使用了全局行為修飾符 g ,則每次返回的結果是不同的,但是倘若你不使用全局行為修飾符 g 就會發現每次返回的結果是第一次匹配的結果。
未使用全局行為修飾符 g :
// 未使用全局行為修飾符 gvar reg = /d/;var str = 'asd123jkl';console.log(reg.exec(str));// [ '1', index: 3, input: 'asd123jkl' ]console.log(reg.exec(str));// [ '1', index: 3, input: 'asd123jkl' ]使用全局行為修飾符 g :
// 使用全局行為修飾符 greg = /d/g;console.log(reg.exec(str));// [ '1', index: 3, input: 'asd123jkl' ]console.log(reg.exec(str));// [ '2', index: 4, input: 'asd123jkl' ]console.log(reg.exec(str));// [ '3', index: 5, input: 'asd123jkl' ]console.log(reg.exec(str));// null-4). RegExp 繼承的方法 :
與 Array 、Date ...... 一樣,RegExp 作為引用類型之一自然也是從 Object 哪里繼承了一些列方法比如 : toString()、toLocaleString()、valueOf() 。只不過前兩者返回的是正則表達式的字符串表示而 valueOf 返回的是正則表達式本身。
var reg = /d+/ig;console.log(reg.toString());// /d+/giconsole.log(reg.toLocaleString());// /d+/giconsole.log(reg.valueOf());// /d+/gi-5). RegExp 構造函數屬性 :
RegExp 的構造函數屬性是針對最近一次的匹配行為來說的。
var reg = /d(d)+/m; var str = 'asd123jkl';console.log(reg.exec(str));// ["123", "3", index: 3, input: "asd123jkl", groups: undefined] console.log(RegExp.input);// asd123jkl console.log(RegExp.lastMatch);// 123 console.log(RegExp.lastParen);// 3 console.log(RegExp.leftContext);// asd console.log(RegExp.rightContext);// jkl但其實這些屬性都有著自己的別名,也就是短屬性,雖然短屬性寫起來比較簡便但是其語義化不是特別友好,所以這里筆者推薦大家在沒有特殊的情況最好是還是使用長屬性名的方式。
就是說上面那些代碼可以替換成 :
var reg = /d(d)+/m; var str = 'asd123jkl';console.log(reg.exec(str));// (2) ["123", "3", index: 3, input: "asd123jkl", groups: undefined] console.log(RegExp['$_']);// asd123jkl console.log(RegExp['$&']);// 123 console.log(RegExp['$+']);// 3 console.log(RegExp['$`']);// asd console.log(RegExp["$'"]);// jkl值得注意的是不可以這樣 RegExp.$_ 使用,應該通過下標法來訪問 ,應該像這樣 RegExp['$_']。
=> 還有 9 個用于存儲捕獲組的構造函數屬性
$1、$2、$3 ... $9
var reg = /(..)or(.)/; var str = 'short'; console.log(reg.exec(str));// (3) ["short", "sh", "t", index: 0, input: "short", groups: undefined] console.log(RegExp.$1);// sh console.log(RegExp['$2']);// t-6). 正則元字符 :
(1). d 匹配一個數字元素
var reg = /d/; var str = 's0s'; console.log(reg.exec(str));// ["0", index: 1, input: "s0s", groups: undefined](2). D 匹配一個非數字元素
var reg = /D/; var str = 's0s'; console.log(reg.exec(str));// ["s", index: 0, input: "s0s", groups: undefined](3). b 匹配一個單詞邊界
var reg = /s0sb/; var str = 's0sly'; console.log(reg.exec(str));// null var reg = /s0sb/; var str = 's0s ly'; console.log(reg.exec(str));// ["s0s", index: 0, input: "s0s ly", groups: undefined](4). B 匹配一個非單詞邊界
var reg = /s0sB/; var str = 's0sly'; console.log(reg.exec(str));// ["s0s", index: 0, input: "s0sly", groups: undefined] var reg = /s0sB/; var str = 's0s ly'; console.log(reg.exec(str));// null(5). w 匹配一個 [a-z0-9A-Z_] 中的字符
var reg = /w+/; var str = 'a1A_$%^<>?>"L:"O"'; console.log(reg.exec(str));// ["a1A_", index: 0, input: "a1A_$%^<>?>"L:"O"", groups: undefined](6). W 匹配一個非 [a-zA-Z0-9_] 中的字符
var reg = /W+/; var str = 'a1A_$%^<>?>"L:"O"'; console.log(reg.exec(str));// $%^<>?>"(7). s 匹配一個空白字符,包括(n、r、t、b) 。
var reg = /sss/; var str = '1s s1'; console.log(reg.exec(str));// ["s s", index: 1, input: "1s s1", groups: undefined](8). S 匹配一個非空白字符
var reg = /sSs/; var str_1 = '1s s1'; var str_2 = '1s0s1'; console.log(reg.exec(str_1));// null console.log(reg.exec(str_2));// ["s0s", index: 1, input: "1s0s1", groups: undefined](9). . 匹配一個除 "n" 之外的任意字符
var reg = /./; var str_1 = 'n'; var str_2 = 'sn'; console.log(reg.exec(str_1));// null console.log(reg.exec(str_2));// ["s", index: 0, input: "s?", groups: undefined](10). {m} 匹配一個元素
var reg = /d{1}/; var str = 'abc123def456'; console.log(reg.exec(str));// ["1", index: 3, input: "abc123def456", groups: undefined](11). {m,n} 匹配 m ~ n 個元素
var reg = /d{2,3}/; var str = 'abc123def456'; console.log(reg.exec(str));// ["123", index: 3, input: "abc123def456", groups: undefined](12). {n,} 匹配至少 n 個元素
var reg = /d{3,}/; var str = 'abc1234'; console.log(reg.exec(str));// ["1234", index: 3, input: "abc1234", groups: undefined](13). * 匹配 0 個 或 多個 字符,相當于 {0,}
var reg = /d*/; var str = 'abc1234'; console.log(reg.exec(str));// ["", index: 0, input: "abc1234", groups: undefined]至于上面這個示例為什么返回 "" 呢?那是因為 * 本身匹配 0 ~ 多個 包括 0 個,所以當代碼執行到 'a...' 的時候就停止了,因為沒有匹配到,符合條件所以就不向下進行了。所以返回 "" 。
如果我們先將數字放在前面呢? 就會匹配多個數字
var reg = /d*/; var str = '1234abc456'; console.log(reg.exec(str));// ["1234", index: 0, input: "1234abc456", groups: undefined](14). + 匹配一個或多個字符,相當于{1,}
var reg = /d+/; var str = 'abc1234'; console.log(reg.exec(str));// ["1234", index: 3, input: "abc1234", groups: undefined](15). ? 匹配零個或一個字符,相當于{0,1}
var reg = /d?/; var str = 'abc1234'; console.log(reg.exec(str));// ["", index: 0, input: "abc1234", groups: undefined](16). ^ 限定后面最近位置的元素必須在字符串的最開
var reg = /^ad/; var str_1 = 'b123'; var str_2 = 'a123'; console.log(reg.exec(str_1));// null console.log(reg.exec(str_2));// ["a1", index: 0, input: "a123", groups: undefined](17). $ 與 ^ 相反,限定前面最近位置的元素必須在字符串的末尾
var reg = /da$/; var str_1 = '1ab'; var str_2 = '1a'; console.log(reg.exec(str_1));// null console.log(reg.exec(str_2));// ["1a", index: 0, input: "1a", groups: undefined](18). | 正則中的或,只不過左右兩邊被當作是一個整體
var reg = /d+|asd/; var str_1 = '123456'; var str_2 = 'asd'; console.log(reg.exec(str_1));// ["123456", index: 0, input: "123456", groups: undefined] console.log(reg.exec(str_2));// ["asd", index: 0, input: "asd", groups: undefined](19). [ ... ] 代表匹配 [ ... ] 內任意一個元素
var reg = /[a,b,c]/; var str = 'apple'; console.log(reg.exec(str));// ["a", index: 0, input: "apple", groups: undefined] var reg = /[a-zA-Z0-9_]+/g; var str = 'apPle 1 _'; console.log(reg.exec(str));// ["apPle", index: 0, input: "apPle 1 _", groups: undefined] console.log(reg.exec(str));// ["1", index: 6, input: "apPle 1 _", groups: undefined] console.log(reg.exec(str));// ["_", index: 8, input: "apPle 1 _", groups: undefined] console.log(reg.exec(str));// null(20). ( ... ) 分組,匹配完大正則再匹配小括號內的小正則
var reg = /person(d)/; var str = 'hello person9'; console.log(reg.exec(str)); console.log(RegExp.$1);(21). [^ ... ] 反字符集合,非 [ ... ] 中的任何一個元素
var reg = /[^a,b,c]/; var str = 'apple'; console.log(reg.exec(str));// ["p", index: 1, input: "apple", groups: undefined](22). ( ... )n 分組引用,引用一個分組中的值
var reg = /(w)(w)2w/; var str = 'woow'; console.log(reg.exec(str));// (2) ["woow", "o", index: 0, input: "woow", groups: undefined] var reg = /(w)(w)2w/; var str = 'woow'; console.log(reg.exec(str));// ["woow", "w", "o", index: 0, input: "woow", groups: undefined](23). Xxx(?= ... )正向預查,匹配符合規則的字符串,其中括號 () 中的不參與匹配只參與查找。如下示例查找后面是 world 的 Hello 。
var reg = /Hello (?=World)/; var str_1 = 'Hello World!'; var str_2 = 'Hi World'; var str_3 = 'World Hello';console.log(reg.exec(str_1));// ["Hello ", index: 0, input: "Hello World!", groups: undefined] console.log(reg.exec(str_2));// null console.log(reg.exec(str_3));// null(24). Xxx(?! ... )負向預查,匹配符合規則的字符串,其中括號 () 中的不參與匹配只參與查找。如下示例查找后面不是 world 的 Hello 。
var reg = /Hello (?!World)/; var str_1 = 'Hello World!'; var str_2 = 'Hi World'; var str_3 = 'Hello LJ';console.log(reg.exec(str_1));// .null console.log(reg.exec(str_2));// null console.log(reg.exec(str_3));// ["Hello ", index: 0, input: "Hello LJ", groups: undefined](25). ?: 匹配不捕獲,JavaScript 不是盡可能多的匹配元素嘛,所以稱之為貪婪模式,從分組那塊就可以看出來,但是有些時候我們不需要再去匹配分組里面的內容,該怎么辦呢? 通過匹配不捕獲來搞!
var reg = /w(?:w)ww/; var str = 'woow'; console.log(reg.exec(str));// ["woow", index: 0, input: "woow", groups: undefined] console.log(RegExp.$1);// " "這次并沒有去匹配分組里面的內容,但是倘若這個時候來一個分組引用會發生什么事情?
var reg = /w(?:w)1w/; var str = 'woow'; console.log(reg.exec(str));// null console.log(RegExp.$1);// " "結果肯定是匹配不到,因為分組都沒有了,所以分組引用也失效了,所以匹配 ww""w 肯定匹配不到,故返回了 null 值。
-7). 支持正則的字符串方法
(1). match( ... ) 方法 查找指定索引對應位置的字符
var reg = /d{1,}/; var str = 's2019s'; console.log(str.match(reg));// ["2019", index: 1, input: "s2019s", groups: undefined](2). search() 方法 查找指定字符所在位置的索引
var reg = /d{1,}/; var str = 's2019s'; console.log(str.search(reg));// 12 字符的位置索引為 1 。
(3). replace() 方法 替換與指定的模式相匹配的字符
var reg = /d+/g; var str = '1a2b3c4d5e6f'; console.log(str.replace(reg, '<->'));// <->a<->b<->c<->d<->e<->f-8). exec() 方法與 match() 方法的區別
(1). exec() 是正則的方法,match() 是字符串的方法。
(2). exec() 方法與 match() 方法在處理全局行為修飾符、分組上面有著不同之處
- exec() 方法在處理全局行為修飾符的時候 。所匹配到的全部結果不會一次出現,會在后面的執行中陸續出現,而 match() 方法在處理全局訪問修飾符的時候會將匹配到的結果一次展示出來。
- exec() 方法與 match() 方法處理分組的時候相同。
- exec() 方法與 match() 方法在處理全局行為修飾符 + 分組的時候不同。
因為此時 exec() 方法 會忽視全局行為修飾符,match() 方法 會忽視分組。
-9). i、m、g 行為修飾符
(1). i 大小寫不敏感
var reg = /[a-z]+/i; var str = 'A1b2C3d4e5F6'; console.log(reg.exec(str));// ["A", index: 0, input: "A1b2C3d4e5F6", groups: undefined](2). m 多行匹配
var reg = /d/; var str = 'sn2'; console.log(reg.exec(str));// ["2", index: 2, input: "s?2", groups: undefined] reg = /^d/; console.log(reg.exec(str));// null reg = /^d/m; console.log(reg.exec(str));// ["2", index: 2, input: "s?2", groups: undefined]最開始可以匹配到 2 是因為最開始僅僅是為了匹配到 2 也并未添加其它的限制,其實 sn2 實際的樣子是這樣的 :
但實際上除了使用 行為修飾符 m ,否則不管使用了多少個 換行符都只有一個開頭與結尾。所以,最開始我們可以匹配到 2 因為那時我們是在結尾除匹配到的 2 。
但是第二次匹配的時候就無法匹配的 2 。是因為我們添加了一個限定符 ^ ,所以整個正則表達式就變成了匹配一個 開頭是2 的字符,但是我們并沒有使用 行為修飾符 m,所以整個字符串不管有多少處換行符都只有一個開頭與結尾可見開頭的是 s 而非 2 所以無法匹配到 。
但是當我們使用 行為修飾符 m 的時候,會把每一處換行符都定位成新的開頭與結尾,所以針對于 第三次匹配實際上匹配了兩次,第一次到第一行 發現是 s 不是 2 。沒有匹配到,所以又到第二行匹配發現是 2 。所以就匹配到了。
(3). g 全局查找
var reg = /d/; var reg_2 = /d/g; var str = '1a2b3c4d5e6f'; console.log(reg.exec(str));// ["1", index: 0, input: "1a2b3c4d5e6f", groups: undefined] console.log(reg.exec(str));// ["1", index: 0, input: "1a2b3c4d5e6f", groups: undefined] console.log(reg.exec(str));// ["1", index: 0, input: "1a2b3c4d5e6f", groups: undefined]console.log(reg_2.exec(str));// ["1", index: 0, input: "1a2b3c4d5e6f", groups: undefined] console.log(reg_2.exec(str));// ["2", index: 2, input: "1a2b3c4d5e6f", groups: undefined] console.log(reg_2.exec(str));// ["3", index: 4, input: "1a2b3c4d5e6f", groups: undefined]好啦,今天就將 JavaScript 中正則表達式的表現介紹到這里了。如果大家用心看筆者想應該還是會有些許收獲的!
下一更 : JavaScript 引用類型之 Function (詳述)
堂皇殿主:(重學前端 - JavaScript(模塊一) 15、引用類型之 Function (詳述)?zhuanlan.zhihu.com如果對本系列文章存在疑問或者想持續跟進或者與其他成員一起交流,歡迎加 QQ 群:
心碼打賞途徑:
微信:
微信打賞支付寶:
支付寶打賞本文屬于作者原創文章,原創不易如需轉發請注明出處或者與作者溝通。本文表述觀點與知乎平臺無關純屬作者個人觀點!!!
歡迎投稿!!!
歡迎大神的加入!!!
總結
以上是生活随笔為你收集整理的判断字符串 正则_(重学前端 - JavaScript(模块一)) 14、引用类型之 RegExp (正则)(详述)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell 打印追加_[转]shell
- 下一篇: android 图片圆角 遮罩_Andr