當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
JS正则表达式(5) = 正则的捕获方法
生活随笔
收集整理的這篇文章主要介紹了
JS正则表达式(5) = 正则的捕获方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正則的捕獲方法
正則捕獲
- 實現正則捕獲的方法 ( RegExp.prototype )
- exec
- test
- 字符串支持正則的方法 ( String.prototype )
- split
- replace
- match
- …
正則的懶惰性
exec
let str = 'aaa111bbb222ccc333'// 正則進行捕獲的前提: 正則表達式能匹配當前字符串, 不匹配結果為null let reg = /^\d+$/; // => 字符串必須是純數字 console.log(reg.test(str)) // => false console.log(reg.exec(str)) // => null// 只有正則表達式能匹配字符串才能開始捕獲 /** * 基于exec實現正則的捕獲:* 1. 結果要么是數組(捕獲成功), 要么是null(捕獲失敗)* 捕獲成功:* 第一項(下標:0): 捕獲成功的內容* 其余項(下標:1~∞): 對應分組()匹配下來的數據* index: 捕獲到的字符串開頭第一個字符下標* input: 被匹配的字符串主體* length: 捕獲到的字符串長度* 2. 執行一次exec, 永遠只能捕獲到第一串符合規則的字符(默認情況下, 懶惰性)* 懶惰性原因是lastIndex的值永遠是0, 每次都是重頭捕獲* 解決辦法: 全局修飾符g*/ let reg = /\d+/; console.log(reg.test(str)) // => true console.log(reg.exec(str)) // => Array [ 0:"111", index: 3, input:"aaa111bbb222ccc333", length: 1, <prototype>: Array[] ]-
exec 捕獲字符串的原理 ( 懶惰性 )
let str = 'aaa111bbb222ccc333' let reg = /\d+//** * 正則對象默認有個屬性叫做lastIndex, 值為0:* reg.lastIndex: 當前正則進行下一次捕捉字符的起始下標*/ console.log(reg.lastIndex) // => 0 正則匹配時從下標0處開始匹配 console.log(reg.exec(str)); // => Array [ 0:"111", index: 3,...] console.log(reg.lastIndex); // => 0 第一次捕獲完成, 其值還是為0 console.log(reg.exec(str)); // => Array [ 0:"111", index: 3,...] console.log(reg.lastIndex); // => 0 第二次捕獲完成, 其值還是為0 ....... console.log(reg.lastIndex); // => 0 第n次捕獲完成, 值還是為0 // 這就是為甚exec匹配到的字符永遠是復合規則的第一托代碼 -
修飾符g進行全局匹配
let str = 'aaa111bbb222ccc333' let reg = /\d+/g; // 加了一個修飾符g, 進行全局匹配, lastIndex會被修改console.log(reg.exec(str)); // => Array [ 0:"111", index: 3,...] console.log(reg.lastIndex); // => 6 console.log(reg.exec(str)); // => Array [ 0:"222", index: 9,...] console.log(reg.lastIndex); // => 12 console.log(reg.exec(str)); // => Array [ 0:"222", index: 9,...] console.log(reg.lastIndex); // => 18, 到最末尾了 console.log(reg.exec(str)); // => null, 從18為開始匹配, 匹配失敗, 結果為null console.log(reg.lastIndex); // => 0, lastIndex重新回歸0 console.log(reg.exec(str)); // => Array [ 0:"111", index: 3,...] console.log(reg.lastIndex); // => 6 ...... // => 一直循環/******************錯誤的使用********************/ // 注意, 只要正則加上了g全局匹配修飾符, 正則的方法每調用一次都會改變reg.laseIndex if(reg.test(str)) {// => 驗證字符串時候和我們的字符串匹配console.log(reg.lastIndex) // => 6, 此值被修改了, exec捕獲的位置從6開始console.log(reg.exec(str)) // Array [ 0:"222", index: 9,...] } /***********************************************/
解決方法
-
捕獲所有符合結果的字符串
// => 寫一個方法, 正則能匹配所有的符合條件的方法(功能和str.match功能相同) ~ function () {function execAll(str) {if (!this.global) {return this.exec(str)}let val = this.exec(str),arr = [];while (val) {arr.push(val[0])val = this.exec(str);}return arr.length == 0 ? null : arr}RegExp.prototype.execAll = execAll; }();let str = 'aaa123bbb222ccc333'; let reg = /\s/g; console.log(reg.execAll(str))console.log('/************************/'); console.log(str.match(/\d+/g)); // => Array(3) [ "123", "222", "333" ] console.log(str.match(/\d+/)); // => Array [ "123" ]
分組的三大作用
分組捕獲
-
捕獲單次
// => 身份證號匹配 let str = '22615819951204161X' let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/; console.log(reg.exec(str)) console.log(str.match(reg)) // Array(7) [ "226158199512041612", "226158", "1995", "12", "04", "1", "X" ] // 第一項: 大正則匹配的結果 /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/ // 其余項: (\d{6}), (\d{4}), (\d{2}), (\d{2})// 但是(\d|X)這一項我們不想要, 在()里面加上?:只匹配不捕獲, 只用其優先級的作用 let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/; console.log(str.match(reg)) // => // Array(7) [ "226158199512041612", "226158", "1995", "12", "04", "1" ]// 如果分組捕獲沒有捕獲到數據, 為defined let re = /^(?:(\d+)|([a-zA-Z]+))$/; let str = '123456'; console.log(str.match(re);); // => Array(3) [ "123456", "123456", undefined ] -
捕獲多次
// => 即想匹配到<<字母>>, 也想匹配到字母 let str = "<<aaa>>哈哈哈<<123>>!!!!<<bbb>><<ccc456>>"; let reg = /<<([a-zA-Z]+)>>/;// 不設置g修飾符, 兩者匹配的結果一致 console.log(reg.exec(str)); console.log(str.match(reg)); // Array [ "<<aaa>>", "aaa" ] Array [ "<<aaa>>", "aaa" ] // 懶惰匹配第一個符合的, 分組匹配內容// 設置g修飾符, match匹配所有, exec還是懶惰匹配(在帶有()分組匹配的情況下) let reg = /<<[a-zA-Z]+>>/g; console.log(reg.exec(str)); console.log(str.match(reg)); // Array [ "<<aaa>>", "aaa" ] // Array [ "<<aaa>>", "<<bbb>>" ]/** * 自己寫一個捕獲所有方法(大正則 + 分組匹配)*/ let str = "<<aaa>>哈哈哈<<123>>!!!!<<bbb>><<ccc456>>"; let reg = /<<([a-zA-Z]+)>>/; let bigArry = [],smallArry = [],val = reg.exec(str); while(val) {let [big, small] = val;bigArry.push(big)smallArry.push(small)val = reg.exec(str) } console.log(bigArry, smallArry) // Array [ "<<aaa>>", "<<bbb>>" ] // Array [ "aaa", "bbb" ]
分組引用
// 如果想讓前面一個字符和后一個或多個字符相同, 可以用()的第三個功能: 分組引用 // 分組引用: \1, 并且只能\1, 如果要多個:\1\1\1 let reg = /^[a-zA-Z]([0-2])\1\1[a-zA-Z]$/;console.log(reg.test('a00b')); // => false console.log(reg.test('a111b')); // => true console.log(reg.test('a222b')); // => true console.log(reg.test('a333b')); // => false console.log(reg.test('a0011b')); // => false console.log(reg.test('a555b')); // => false正則捕獲的貪婪性
let str = 'aaa111bbb222ccc'; let reg1 = /\d+/g; let reg2 = /\d+?/g let reg3 = /\d*?/g// => 正則捕獲的貪婪性: 在默認情況下, 正則都可能盡可能多的取匹配字符串 console.log(str.match(reg1)) // => [ '111', '222', '333' ]// 加上 ? 之后, 正則會盡可能少的匹配字符串, +: 1~∞(1次) *:0~∞(0次) console.log(str.match(reg2)) // => Array(6) [ "1", "1", "1", "2", "2", "2" ] console.log(str.match(reg3)) // => Array(6) [ "", "", "", "", "", "", ... ]問好的五大作用
其他正則的捕獲方法
test捕獲
let str = "<name><age><sex>" let reg = /<([a-zA-Z]+)>/g;console.log(reg.test(str)); // => true console.log(RegExp.$1); // => nameconsole.log(reg.test(str)); // => true console.log(RegExp.$1); // => ageconsole.log(reg.test(str)); // => true console.log(RegExp.$1); // => sexconsole.log(reg.test(str)); // => false, 全部匹配結束, 開始新的循環 console.log(RegExp.$1); // => sexconsole.log(reg.test(str)); // => true console.log(RegExp.$1); // => name// egExp.$1 ~ egExp.$9 : 獲得當前本次正則匹配后, 第一個分組的信息 - 第九個分組的信息replace 字符串中用來實現替換的方法 ( 一般伴隨正則一起使用 )
let str = "今天天氣真好, fuck, 尼瑪的"// => 把 fuck, 尼瑪 這些敏感詞替換成* str = str.replace(/(fuck|尼瑪)/g, '**')console.log(str) // => 今天天氣真好, **, **的replace的分組替換功能 ( replace的功能之一 )
let str = '2020-1-19 14:19 2020-1-19 14:19'; let reg = /(\d{4})-(\d{1,2})-(\d{2}) (\d{2}):(\d{2})/; // 懶惰匹配, 只有一次 console.log(str.replace(reg, "$1年$2月$3日 $4時$5分")) // => 2020年1月19日 14時19分 2020-1-19 14:19let str = '2020-1-19 14:19 2020-1-19 14:19'; let reg = /(\d{4})-(\d{1,2})-(\d{2}) (\d{2}):(\d{2})/g; // 全局匹配, 替換所有 console.log(str.replace(reg, "$1年$2月$3日 $4時$5分")) // => 2020年1月19日 14時19分 2020年1月19日 14時19分replace方法的使用:
/** * str.replace([RegExp], [function])* 1. replace方法每次將正則的規則匹配到字符串一次, 就執行一次函數* let str = '123456';* let reg = /\d/g;* reg.replace(reg, () => { console.log(我被執行); return 11 })* 2. 函數默認接收大正則匹配的結果, $1 $2 $3小分組結果, 匹配下表,原始字符* 3. 函數的返回值就是把匹配的字符串替換的值*/// 1. 不進行分組( 傳入函數中的值: 匹配字符串, 匹配開始下表, 原始字符串 ) str = '1 2 3 4 5 6'; reg = /\d/g; str.replace(reg, (...args) => { console.log(args) // => Array(3) [ "1", 0, "1 2 3 4 5 6" ]return 哈哈; }) // str => 哈哈 哈哈 哈哈 哈哈 哈哈 哈哈// 2. 進行分組( 傳入函數中的值: 匹配字符串, 分組字符, 匹配開始下表, 原始字符串 ) str = '1 2 3 4 5 6'; reg = /\d/g; str.replace(reg, (...args) => { console.log(args) // => Array(4) [ "1", "1", 0, "1 2 3 4 5 6" ]return '嘻嘻'; }) // str => 嘻嘻 嘻嘻 嘻嘻 嘻嘻 嘻嘻 嘻嘻 // 案例: 進行事件的匹配, 并且進行補充 2019年1月20日 => 2019-01-20 let str = '2019年12月1日, 還是2019年2月4日'; let reg = /(\d{4})年(\d{1,2})月(\d{1,2})日/g; str = str.replace(reg, (...args) => {console.log(args);let [big, year, month, day] = args;month = month.length == 1 ? '0' + month : month;day = day.length == 1 ? '0' + day : day;return `${year}-${month}-${day}` }) console.log(str) // => 2019-12-01, 還是2019-02-04總結
以上是生活随笔為你收集整理的JS正则表达式(5) = 正则的捕获方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 传说中的b站mac客户端(支持M1芯片、
- 下一篇: 2020年度阅读数TOP 20文章汇总