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