摘要:本文接上篇,基礎(chǔ)部分相對薄弱的同學(xué)請移步正則表達式學(xué)習(xí)筆記一理論基礎(chǔ)。正則表達式標(biāo)志符全局匹配,即找到所有匹配的。方法返回結(jié)果的格式不一致問題這個問題上文正則表達式學(xué)習(xí)筆記一理論基礎(chǔ)也有體現(xiàn),這里再多帶帶拿來說一說,以加深記憶。
本文接上篇,基礎(chǔ)部分相對薄弱的同學(xué)請移步《JavaScript正則表達式學(xué)習(xí)筆記(一) - 理論基礎(chǔ)》。上文介紹了8種JavaScript正則表達式的屬性,本文還會追加介紹幾種JavaScript正則表達式的屬性(注意是非標(biāo)準(zhǔn)屬性,但很好用)。一. 上文回顧
本文會用到上篇文章部分內(nèi)容,所以簡單回顧下。1.1 JavaScript正則表達式標(biāo)志符
g: 全局匹配,即找到所有匹配的。對應(yīng)屬性RegExp#global。
i: 忽略字母大小寫。對應(yīng)屬性RegExp#ingoreCase。
m: 多行匹配,只影響^和$,二者變成行的概念,即行開頭和行結(jié)尾。對應(yīng)屬性RegExp#multiline。
u: ES6新增。含義為“Unicode 模式”,用來正確處理大于uFFFF的 Unicode 字符。也就是說,會正確處理四個字節(jié)的 UTF-16 編碼。對應(yīng)屬性RegExp#unicode。
y: ES6新增。y修飾符的作用與g修飾符類似,也是全局匹配,后一次匹配都從上一次匹配成功的下一個位置開始。不同之處在于,g修飾符只要剩余位置中存在匹配就可,而y修飾符確保匹配必須從剩余的第一個位置開始,這也就是“粘連”的涵義。對應(yīng)屬性RegExp#sticky。
1.2 適用于Javascript正則表達式的方法上篇文章《JavaScript正則表達式學(xué)習(xí)筆記(一) - 理論基礎(chǔ)》介紹了適用于JavaScript正則表達式模式匹配的相關(guān)API共有6種,RexExp提供2個,String提供4個,如下:
1. RegExp#test // 適用于:驗證、提取 2. RegExp#exec // 適用于:驗證、提取 3. String#search // 適用于:驗證、提取 4. String#match // 適用于:驗證、提取 5. String#split // 適用于:切分 6. String#replace // 適用于:提取、替換二. JavaScript正則表達式的四種操作
正則表達式是用于匹配字符串中字符組合的模式, 其核心內(nèi)容便是模式匹配。也就是說,不論進行那種操作,首先要有模式匹配,有了模式匹配之后,才能進行驗證、替換、切分、提取這四種操作。
2.1 驗證驗證應(yīng)該是前端程序員寫正則表達式用的最多的方法吧,比如表單驗證之類的。可以實現(xiàn)驗證的方法有4種。
光說不練假把式,光練不說傻把式,又練又說才是真把式?。那么,請看下面的例子?:
如果正則表達式與指定的字符串匹配 ,返回true,否則false。得到的結(jié)果可以直接使用。
const str = "jing ke tong xue 666"; let reg1 = /d{4}/; let res1 = reg1.test(str); console.log(res1); // => false let reg2 = /ke/; let res2 = reg2.test(str); console.log(res2); // => true let reg3 = /d{3}/; let res3 = reg3.test(str); console.log(res3); // => true
下面我們看一個匹配身份證的示例:
const str1 = "411199909096896"; const str2 = "411425199909096896"; const str3 = "41142519990909689x"; const str4 = "41142519990909689X"; const reg = /^(d{15}|d{17}[dxX])$/; let res1 = reg.test(str1); let res2 = reg.test(str2); let res3 = reg.test(str3); let res4 = reg.test(str4); console.log(res1, res2, res3, res4); // => true true true true
不過好在網(wǎng)上有很多可視化工具供我們使用,看一下下圖可能就豁然開朗。
看圖分析:這里豎杠|的優(yōu)先級最低,所以正則分成了兩部分d{15}和d{17}[dxX]
d{15} 表示15位連續(xù)數(shù)字
d{17}[dxX] 表示17位連續(xù)數(shù)字,最后一位可以是數(shù)字,也可以大寫或小寫字母 "x"
下面我們再看一個稍微復(fù)雜一點的案例,匹配IPV4地址:
const str = "192.168.0.1"; let reg = /^((0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5]).){3}(0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5])$/; let res = reg.test(str); console.log(res); // => true
上面那個正則表達式初看起來有點嚇人哈?,這就是傳說中的寫正則不難,讀正則難。先看下面可視化視圖:
此正則表達式主體結(jié)構(gòu)大致如下:
((…).){3}(…)
兩個(...)是相同的內(nèi)容,因此文字描述為3位數(shù)字.3數(shù)字.3位數(shù)字.3位數(shù)字。
下面我們具體分析(...)也就是(0{0,2}d|0?d{2}|1d{2}|2[0-4]d|25[0-5]),多帶帶看一下這段代碼的可視化視圖:
看圖分析,它是一個多選結(jié)構(gòu),分成5個部分:
0{0,2}d: 匹配一位數(shù),包括 "0" 補齊的。比如,"9"、"09"、"009"
0?d{2}: 匹配兩位數(shù),包括 "0" 補齊的,也包括一位數(shù)
1d{2}: 匹配 "100" 到 "199"
2[0-4]d: 匹配 "200" 到 "249"
25[0-5]: 匹配 "250" 到 "255"
不要被看起來復(fù)雜的正則表達式嚇到,乍看起來復(fù)雜的不要不要的,那我們就把它像洋蔥一樣,一層一層剝開它的心,擁抱它,然后扒光它。
如果匹配成功,返回一個Array,否則返回null。得到的結(jié)果兩次取反取得true或者false使用。
const str = "jing ke tong xue 666"; let reg1 = /d{4}/; let res1 = reg1.exec(str); console.log(res1); console.log(!!res1); // => null // => false let reg2 = /ke/; let res2 = reg2.exec(str); console.log(res2); console.log(!!res2); // => ["ke", index: 5, input: "jing ke tong xue 666", groups: undefined] // => true let reg3 = /d{3}/; let res3 = reg3.exec(str); console.log(res3); console.log(!!res3); // => ["666", index: 17, input: "jing ke tong xue 666", groups: undefined] // => true
如果匹配成功,返回正則表達式在字符串中首次匹配項的索引(大于等于0),否則,返回 -1。如果為了和上面的方法保持一致返回true或false,這里需要借助一次按位非操作符(~)。
const str = "jing ke tong xue 666"; let reg1 = /d{4}/; let res1 = str.search(reg1); console.log(res1); console.log(!!~res1); // => -1 // => flase let reg2 = /ke/; let res2 = str.search(reg2); console.log(res2); console.log(!!~res2); // => 5 // => true const reg3 = /d{3}/; let res3 = str.search(reg3); console.log(res3); console.log(!!~res3); // => 17 // => true
如果匹配成功,返回一個Array,否則返回null。得到的結(jié)果兩次取反取得true或者false使用。
const str = "jing ke tong xue 666"; let reg1 = /d{4}/; let res1 = str.match(reg1); console.log(res1); console.log(!!res1); // => null // => flase let reg2 = /ke/; let res2 = str.match(reg2); console.log(res2); console.log(!!res2); // => ["ke", index: 5, input: "jing ke tong xue 666", groups: undefined] // => true let reg3 = /d{3}/; let res3 = str.match(reg3); console.log(res3); console.log(!!res3); // => ["666", index: 17, input: "jing ke tong xue 666", groups: undefined] // => true2.2 替換
有時候找到了對象往往不是我們最終的目的,找到了對象做點什么才是我們想要的?。
這里我們看一看找到后的替換操作,我本人的常用場景就是格式化日期和刪除空格。
// 把YYYY/MM/DD格式的日期替換成YYYY-MM-DD格式。 const str1 = "jing-ke-tong-xue"; let res1 = str1.replace(/-/g, " "); console.log(res1); // => jing ke tong xue // 刪除前后空格, 為了直觀這里把前后空格替換成“刪除了的空格” const str2 = " jing ke tong xue "; let res2 = str2.replace(/^s|s$/g, "刪除了的空格"); console.log(res2); // => 刪除了的空格jing ke tong xue刪除了的空格 // 據(jù)說下面這種方法速度比較快 const str3 = " jing ke tong xue "; let res3 = str3.replace(/^s/, "刪除了的空格").replace(/s$/, "刪除了的空格"); console.log(res3); // => 刪除了的空格jing ke tong xue刪除了的空格2.3 切分
切蘿卜切蘿卜切切切,包餃子包餃子捏捏捏?。在這里,所謂切分就是把字符串切的一段一段的。
// 按空格切分 const str = "jing ke tong xue"; console.log(str.split(/s/)); // => ["jing", "ke", "tong", "xue"] const str2 = "jing * ke ¥ tong ^xue"; console.log(str2.split(/s*s|s¥s|s^/)) // => ["jing", "ke", "tong", "xue"]2.4 提取
有時候驗證、替換、切分都不是目的,我們需要提取出來對我們有用的信息,那么就需要提取了。此時需要用到下篇會寫到的“括號”(分組引用或者分組捕獲)。
這里有一個正則將會貫穿本小節(jié),我們先提前分析一下:
// 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg = /(d{4})D(d{2})D(d{2})/g;
可視化視圖:
看圖說話:從上圖可知這段正則的意思就是:4個數(shù)字后跟一個非數(shù)字再跟2個數(shù)字再跟一個非數(shù)字再跟2個數(shù)字。形如:4個數(shù)字-2個數(shù)字-2個數(shù)字格式。
2.4.1 使用exec方法
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg = /(d{4})D(d{2})D(d{2})/g; // 上篇文章有說:`exex`方法匹配到一次就會返回結(jié)果,想要下一個結(jié)果必須再次調(diào)用 console.log(reg.exec(str)); console.log(reg.exec(str)); // => ["2018-04-04", "2018", "04", "04", index: 16, input: "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是2018-40-40,提取日期測試字符串", groups: undefined] // => ["6666-66-66", "6666", "66", "66", index: 34, input: "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串", groups: undefined]
2.4.2 使用match方法
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg1 = /(d{4})D(d{2})D(d{2})/; console.log(str.match(reg1)); // 沒有g(shù)標(biāo)識符返回結(jié)果與match無異 // => ["2018-04-04", "2018", "04", "04", index: 16, input: "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串", groups: undefined] // 帶有g(shù)標(biāo)識符,結(jié)果數(shù)組只包含匹配結(jié)果 // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg2 = /(d{4})D(d{2})D(d{2})/g; console.log(str.match(reg2)); // => ["2018-04-04", "6666-66-66"]
2.4.3 使用replace方法
在上篇文章步《JavaScript正則表達式學(xué)習(xí)筆記(一) - 理論基礎(chǔ)》的理論基礎(chǔ)中提到replace方法的第二個參數(shù)可以是一個函數(shù),函數(shù)接收的參數(shù)包含我們需要的信息。
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg1 = /(d{4})D(d{2})D(d{2})/; let res1 = []; str.replace(reg1, function(match, year, month, day, offset, string) { res1.push(match, year, month, day, offset, string); }); console.log(res1); // => ["2018-04-04", "2018", "04", "04", 16, "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"] // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg2 = /(d{4})D(d{2})D(d{2})/g; let res2 = []; str.replace(reg2, function(match, year, month, day, offset, string) { res2.push(match); }); console.log(res2); // => ["2018-04-04", "6666-66-66"]
從輸出效果來看,replace方法可以達到模擬match方法的效果。這就是傳說中的條條大路通羅馬No roads can"t lead to Rome(哼...哼哼...翻譯是我故意的嗷?)
2.4.4 使用test方法
此方法會用到RegExp.$1-$9這一非標(biāo)屬性,這里只是使用,下文會做介紹。
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg = /(d{4})D(d{2})D(d{2})/; reg.test(str); // RegExp.$1-$9非標(biāo)屬性,但是目的達到了,請勿用于生產(chǎn)環(huán)境 let res = [RegExp.$1, RegExp.$2, RegExp.$3]; console.log(res); // => ["2018", "04", "04"]
2.4.4 使用search方法
此方法會用到RegExp.$1-$9這一非標(biāo)屬性,這里只是使用,同樣留到下文介紹。
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg = /(d{4})D(d{2})D(d{2})/; str.search(reg); // RegExp.$1-$9非標(biāo)屬性,但是目的達到了,請勿用于生產(chǎn)環(huán)境 let res = [RegExp.$1, RegExp.$2, RegExp.$3]; console.log(res); // => ["2018", "04", "04"]
到這里正則表達式的驗證、替換、切分、提取已經(jīng)介紹完了,有些操作是取巧的做法,也不建議在生產(chǎn)環(huán)境使用,不過某些特殊情況除外。至于哪些情況是特殊情況,具體問題具體分析吧?。
三. 注意要點在本文 1.2 小節(jié)提到了6種可以用于正則操作的方法,RegExp提供2種,String提供4種。本章節(jié)就圍繞這幾種方法展開。
3.1 match方法返回結(jié)果的格式不一致問題這個問題上文《JavaScript正則表達式學(xué)習(xí)筆記(一) - 理論基礎(chǔ)》也有體現(xiàn),這里再多帶帶拿來說一說,以加深記憶。
const str = "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串"; // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg1 = /(d{4})D(d{2})D(d{2})/; console.log(str.match(reg1)); // => ["2018-04-04", "2018", "04", "04", index: 16, input: "提取日期測試字符串,今天的日期是2018-04-04,今天的日期不是6666-66-66,提取日期測試字符串", groups: undefined] // 這里為了簡單測試,只考慮了日期格式,沒考慮日期的合理性 let reg2 = /(d{4})D(d{2})D(d{2})/g; console.log(str.match(reg2)); // => ["2018-04-04", "6666-66-66"] // 這個正則只是來客串說明問題,沒有其他意義 let reg3 = /.^/; console.log(str.match(reg3)); // => null // 這個正則只是來客串說明問題,沒有其他意義 let reg4 = /.^/g; console.log(str.match(reg4)); // => null
當(dāng)沒有g標(biāo)識符時,返回的結(jié)果為標(biāo)準(zhǔn)匹配格式,包含完整的匹配信息。
當(dāng)有g標(biāo)識符時,返回的結(jié)果為所有匹配結(jié)果組成的數(shù)組。
當(dāng)匹配不成功時,無論有沒有標(biāo)識符(包括igmyu的任意組合),都返回null。
3.2 search和match的參數(shù)問題話不多說,先看代碼:
// 為了說明問題,日期格式選擇了用“.”連接,因為“.”在正則中屬于元字符 const str = "2018.04.04"; console.log(str.search(".")); console.log(str.search(/./)); console.log(str.search(".")); console.log(str.search(/./)); // => 0 // => 0 // => 4 // => 4 console.log(str.match(".")); console.log(str.match(/./)); console.log(str.match(".")); console.log(str.match(/./)); // => ["2", index: 0, input: "2018.04.04", groups: undefined] // => ["2", index: 0, input: "2018.04.04", groups: undefined] // => [".", index: 4, input: "2018.04.04", groups: undefined] // => [".", index: 4, input: "2018.04.04", groups: undefined] console.log(str.replace(".", "-")); console.log(str.replace( /./, "-")); console.log(str.replace(".", "-")); console.log(str.replace(/./, "-")); // => 2018-04.04 // => -018.04.04 // => 2018-04.04 // => 2018-04.04 console.log(str.split(".")); console.log(str.split(/./)); console.log(str.split(".")); console.log(str.split(/./)); // => ["2018", "04", "04"] // => ["", "", "", "", "", "", "", "", "", "", ""] // => ["2018.04.04"] // => ["2018", "04", "04"]
從上述代碼可以看出search方法和match方法會將接收到的字符串參數(shù)轉(zhuǎn)為正則,而replace方法和split方法不會轉(zhuǎn)換,所以使用時請注意。
3.3 exec和match的王者之爭王者之爭第一回合:
const str = "2018-04-04"; let reg1 = /(d+)/; let reg2 = /(d+)/g; console.log(reg1.exec(str)); console.log(reg2.exec(str)); // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] console.log(str.match(reg1)); console.log(str.match(reg2)); // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] // ["2018", "04", "04"]
g標(biāo)識符對exec方法沒有產(chǎn)生影響,但是改變了match方法的行為。沒主見啊,沒主見。
沒有g標(biāo)識符時,match返回標(biāo)準(zhǔn)匹配參數(shù),有g標(biāo)識符時返回了匹配結(jié)果的集合。但是對于exec方法無論有沒有g標(biāo)識符都返回了同樣的結(jié)果。不智能啊,不智能。
這一回合實力相差不大,看不出孰優(yōu)孰劣。
王者之爭第二回合:
const str = "2018-04-04"; let reg1 = /(d+)/; let reg2 = /(d+)/g; console.log(reg2.lastIndex); console.log(reg2.exec(str)); // => 0 // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] console.log(reg2.lastIndex); console.log(reg2.exec(str)); // => 4 // => ["04", "04", index: 5, input: "2018-04-04", groups: undefined] console.log(reg2.lastIndex); console.log(reg2.exec(str)); // => 7 // => ["04", "04", index: 8, input: "2018-04-04", groups: undefined] console.log(reg2.lastIndex); console.log(reg2.exec(str)); // => 10 // => null // 上一次匹配失敗,這一次從頭開始 console.log(reg2.lastIndex); console.log(reg2.exec(str)); // => 0 // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] // 沒有g(shù)標(biāo)識符時match方法每次都從第一位開始匹配 console.log(str.match(reg1)); console.log(str.match(reg1)); // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] // => ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined]
這一回合沒有懸念,exec方法勝出。不過上面的寫法未免太過繁瑣。請看下面當(dāng)exec遇上while:
const str = "2018-04-04"; let reg = /(d+)/g; // 結(jié)合while流程控制語句 let res; while (res = reg.exec(str)) { console.log(reg.lastIndex, res); } // => 4 ["2018", "2018", index: 0, input: "2018-04-04", groups: undefined] // => 7 ["04", "04", index: 5, input: "2018-04-04", groups: undefined] // => 10 ["04", "04", index: 8, input: "2018-04-04", groups: undefined]
王者之爭至此結(jié)束。exec要比match強大那么一點哈。
3.4 除了exec方法,g標(biāo)識符對test方法也有影響上篇文章曾經(jīng)提到 lastIndex 是正則表達式的一個可讀可寫的整型屬性,用來指定下一次匹配的起始索引。 也就是說,只要正則還是那個正則,當(dāng)存在g標(biāo)識符的時候lastIndex都會做出相應(yīng)的改變,要匹配的字符串可以不是同一個。
const str1 = "2018-04-04"; const str2 = "2018-04-05"; const str3 = "2018-04-06"; const str4 = "2018-04-07"; const str5 = "2018-04-08"; let reg = /(d+)/g; console.log(reg.lastIndex); console.log(reg.test(str1)); // => 0 // => true console.log(reg.lastIndex); console.log(reg.test(str2)); // => 4 // => true console.log(reg.lastIndex); console.log(reg.test(str3)); // => 7 // => true console.log(reg.lastIndex); console.log(reg.test(str4)); // => 10 // => false console.log(reg.lastIndex); console.log(reg.test(str5)); // => 0 // => true
當(dāng)沒有g操作符時,始終從0開始匹配,這里就不做演示了。
3.5 split方法注意事項const str = "2018-04-04"; console.log(str.split("-")); console.log(str.split("-", 2)); console.log(str.split("-", 10)); // => ["2018", "04", "04"] // => ["2018", "04"] // => ["2018", "04", "04"] let reg1 = /-/; let reg2 = /(-)/; console.log(str.split(reg1)); console.log(str.split(reg2)); // => ["2018", "04", "04"] // => ["2018", "-", "04", "-", "04"]
split方法可以接收第二個參數(shù)指定返回數(shù)組長度,第二個參數(shù)只有小于實際返回數(shù)組長度時才生效。
當(dāng)split接收的正則表達式種包含分組模式時,返回的結(jié)果數(shù)組包含分組匹配項。
3.6 強大的replace方法replace方法不但可以接收一個函數(shù)作為第二個參數(shù)(前面已經(jīng)體現(xiàn),這兒不重復(fù)示例),也可以接收一個字符串作為第二個參數(shù)。此處的字符串除了是一個普通的替換字符串之外,也可以是一個特殊變量。本小節(jié)以實際示例介紹一下這幾個特殊變量(第一篇理論基礎(chǔ)有提及)。
變量名 | 代表的值 |
---|---|
$$ | 插入一個 "$"。 |
$& | 插入匹配的子串。 |
$` | 插入當(dāng)前匹配的子串左邊的內(nèi)容。 |
$" | 插入當(dāng)前匹配的子串右邊的內(nèi)容。 |
$n | 匹配第n個分組里捕獲的文本,n是不大于100的正整數(shù)。 |
哇哈,是時候表演真正的技術(shù)了,下面我們就來看看replace的能力。
const str1 = "3 6 9"; let reg1 = /d/g; // 被$包圍 console.log(str1.replace(reg1, "$$$&$$")); // => $3$ $6$ $9$ // 分身 console.log(str1.replace(reg1, "$&$&$&")); // => 333 666 999 // 分身相加 let reg2 = /(d)s(d)s(d)/; console.log(str1.replace(reg2, "$1$1$1+$2$2$2$2=$3$3$3")); // => 333+6666=999 // 你愛我我愛你 console.log(str1.replace(reg2, "$1$1$1+$2$2$2=$2$2$2+$1$1$1=$3$3$3=>?")); // => 333+666=666+333=999=>? const str2 = "3?6?9"; let reg3 = /?|?/g; console.log(str2.replace(reg3, "($&的左邊是: $`, 右邊是: $")")); // => 3(?的左邊是: 3, 右邊是: 6?9)6(?的左邊是: 3?6, 右邊是: 9)9
突然間感覺王者之爭不應(yīng)該只讓exec和match參加,replace這么強大,也應(yīng)該參與其中的嘛?。
3.7 構(gòu)造函數(shù)和字面量問題這里沒有什么懸念,一般建議優(yōu)先使用字面量的方式創(chuàng)建正則表達式,因為構(gòu)造函數(shù)中需要對元字符轉(zhuǎn)義,會多寫很多的反斜杠。當(dāng)然特殊情況還是要用構(gòu)造函數(shù)。
const str = "2018-04-04"; let reg1 = /(d{4})D(d{2})D(d{2})/; console.log(reg1); console.log(reg1.test(str)); // => /(d{4})D(d{2})D(d{2})/ // => true let reg2 = new RegExp("(d{4})D(d{2})D(d{2})"); console.log(reg2); console.log(reg2.test(str)); // => /(d{4})D(d{2})D(d{2})/ // => false let reg3 = new RegExp("(d{4})D(d{2})D(d{2})"); console.log(reg3); console.log(reg3.test(str)); // => /(d{4})D(d{2})D(d{2})/ // => true
下面是特殊情況:
let name = "user name"; // user name是一個變量 const str = "2018-04-04 user name"; // 在字面量中,無法實現(xiàn)動態(tài)拼接 let reg1 = /(d{4})D(d{2})D(d{2})D + name/; console.log(reg1); console.log(reg1.test(str)); // => /(d{4})D(d{2})D(d{2})D + name/ // => flase let reg2 = new RegExp("(d{4})D(d{2})D(d{2})D" + "(" + name + ")"); console.log(reg2); console.log(reg2.test(str)); // => /(d{4})D(d{2})D(d{2})D(user name)/ // => true3.8 幾個非標(biāo)屬性
上面用到了RegExp.$1這一非標(biāo)屬性,所謂非標(biāo)屬性,就是此屬性不符合當(dāng)前任何標(biāo)準(zhǔn)規(guī)范。所以,請盡量不要在生產(chǎn)環(huán)境中使用,除非特殊情況并且你能保證以后也不會出錯。
屬性 | 別名 | 說明 |
---|---|---|
RegExp.$1-$9 | 無 | 靜態(tài)、只讀屬性。包含括號子串匹配的正則表達式的靜態(tài)和只讀屬性。只有在正確匹配的情況下才會改變。雖然括號可以無限,但是此屬性最多只能匹配9個。 |
RegExp.input | RegExp.$_ | 靜態(tài)屬性,含有正則表達式最近一次所匹配的字符串。當(dāng)正則表達式上搜索的字符串發(fā)生該變,并且字符串匹配時,input 屬性的值會修改。 |
RegExp.lastMatch | RegExp["$&"] | 靜態(tài)、只讀屬性。含有最近一次匹配到的字符串。屬性的值是只讀的,會在匹配成功時修改。 |
RegExp.lastParen | RegExp["$+"] | 靜態(tài)、只讀屬性,包含匹配到的最后一個子串。會在匹配成功時修改。 |
RegExp.leftContext | RegExp["$`"] | 靜態(tài)、只讀屬性。含有最新匹配的左側(cè)子串。 會在匹配成功時修改。 |
RegExp.rightContext | RegExp["$""] | 靜態(tài)、只讀屬性。含有最新匹配的右側(cè)子串。 會在匹配成功時修改。 |
這幾個屬性平時也基本用不到,了解了解總是好的,請看下面示例:
const str = "a1b2c3d4e5f6"; let reg = /([a-f])([1-6])/g; // 為了倒數(shù)第二個有輸出,這里執(zhí)行兩次exec方法 console.log(reg.exec(str)); console.log(reg.exec(str)); // ["a1", "a", "1", index: 0, input: "a1b2c3d4e5f6", groups: undefined] // ["b2", "b", "2", index: 2, input: "a1b2c3d4e5f6", groups: undefined] console.log(RegExp.$1); console.log(RegExp.$2); // => b // => 2 console.log(RegExp.input); console.log(RegExp.$_); // => a1b2c3d4e5f6 // => a1b2c3d4e5f6 console.log(RegExp.lastMatch); console.log(RegExp["$&"]); // => b2 // => b2 console.log(RegExp.lastParen); console.log(RegExp["$+"]); // => 2 // => 2 console.log(RegExp.leftContext); console.log(RegExp["$`"]); // => a1 // => a1 console.log(RegExp.rightContext); console.log(RegExp["$""]); // => c3d4e5f6 // => c3d4e5f6四. 奇技淫巧
本文寫的也挺長的,剩下的準(zhǔn)備再寫一篇終結(jié)JavaScript正則表達式部分的內(nèi)容。那么本文就先用一個真是案例來做結(jié)尾吧。
JavaScript常用的類型判斷實現(xiàn)
下面這段代碼是在某個框架源碼中見到的,初見之時倍感驚艷(原諒我入行不久見識短?),其中也用到上文提到的split方法,特拿出來分享一下。
let utils = Object.create(null); const types = "Boolean|Number|String|Function|Array|Date|RegExp|Object|Error"; types.split("|").forEach(type => { utils["is" + type] = obj => { return Object.prototype.toString.call(obj) == "[object " + type + "]"; }; }); console.log(utils.isBoolean("true")); console.log(utils.isBoolean(true));
雖然可以將Boolean|Number|String|Function|Array|Date|RegExp|Object|Error存儲為數(shù)組減少一次split切分操作,但是這樣似乎多了點黑科技的感覺。
由于本同學(xué)能力有限,不足之處還望各位大佬同學(xué)指正。
至此,本文完。
第一篇完結(jié): JavaScript正則表達式學(xué)習(xí)筆記(一) - 理論基礎(chǔ)
第二篇完結(jié)(就是本文):JavaScript正則表達式學(xué)習(xí)筆記(二) - 打怪升級
第三篇待更:JavaScript正則表達式學(xué)習(xí)筆記(三) - 終章
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94080.html
摘要:往期回顧打怪升級小程序評論回復(fù)和發(fā)貼功能實戰(zhàn)二填坑手冊小程序生成海報一拆彈時刻小程序生成海報二填坑手冊小程序目錄結(jié)構(gòu)和組件使用心得 showImg(https://segmentfault.com/img/remote/1460000019733090?w=818&h=516); 在學(xué)習(xí)成長的過程中,常常會遇到一些自己從未接觸的事物,這就好比是打怪升級,每次打倒一只怪,都會獲得經(jīng)驗,讓...
摘要:解題思路使用正則表達式地址轉(zhuǎn)問題描述把輸入的地址轉(zhuǎn)換為格式比如解題思路使用位移運算符方法方法找零錢問題問題描述電影院票價為,而觀眾手中的美元面值有,。解題思路為每個面值的美元設(shè)定初始數(shù)量,然后開始對每個數(shù)組值遍歷,根據(jù)不同面值設(shè)定不同規(guī)則。 關(guān)于Codewars:這是一個用于編程練習(xí)的網(wǎng)站,支持多種編程語言。網(wǎng)站首次注冊需要完成兩道題目,之后進入系統(tǒng),類似于打怪升級。通過完成題目來實現(xiàn)...
摘要:分組小括號功能較多有三種功能,作用一,把單獨的項組合成子表達式。作用三,允許后面引用前面的表達式。如果這時的正則表達式是一個非全局的,那么和正則表達式方法拿到的結(jié)果相同。,也可以接受一個正則表達式作為參數(shù)。 正則表達式創(chuàng)建字面量創(chuàng)建,a = /abc/gim;構(gòu)造函數(shù)創(chuàng)建,a = new RegExp(abc,gim)正則表達式中的特殊字符,[...] 方括號中的任意字符[^...] ...
摘要:任務(wù)名稱響應(yīng)式砸蛋頁面任務(wù)背景前輩方方啊最近項目也沒什么事情你看這個砸蛋頁面不是很好看要不你做一個響應(yīng)式砸蛋頁面吧系統(tǒng)鄭方方接下前輩的任務(wù)鄭方方自動解析任務(wù)步驟任務(wù)響應(yīng)式砸蛋頁面與入門閱讀秘籍響應(yīng)式布局制作層搭配搭配控制器完成任務(wù)人物背 任務(wù)名稱:響應(yīng)式砸蛋頁面 任務(wù)背景 前輩:方方啊,最近項目也沒什么事情,你看這個砸蛋頁面不是很好看,要不你做一個響應(yīng)式砸蛋頁面吧? 系統(tǒng):鄭方方接下前...
摘要:任務(wù)名稱響應(yīng)式砸蛋頁面任務(wù)背景前輩方方啊最近項目也沒什么事情你看這個砸蛋頁面不是很好看要不你做一個響應(yīng)式砸蛋頁面吧系統(tǒng)鄭方方接下前輩的任務(wù)鄭方方自動解析任務(wù)步驟任務(wù)響應(yīng)式砸蛋頁面與入門閱讀秘籍響應(yīng)式布局制作層搭配搭配控制器完成任務(wù)人物背 任務(wù)名稱:響應(yīng)式砸蛋頁面 任務(wù)背景 前輩:方方啊,最近項目也沒什么事情,你看這個砸蛋頁面不是很好看,要不你做一個響應(yīng)式砸蛋頁面吧? 系統(tǒng):鄭方方接下前...
閱讀 1478·2021-10-18 13:29
閱讀 2735·2021-10-12 10:18
閱讀 3594·2021-09-22 15:06
閱讀 2608·2019-08-29 17:09
閱讀 2798·2019-08-29 16:41
閱讀 1503·2019-08-29 13:48
閱讀 3237·2019-08-26 13:49
閱讀 3334·2019-08-26 13:34