[JS高程]JavaScript中的RegExp對象
- 2021 年 11 月 23 日
- 筆記
- javascript
1. RegExp
ECMAScript 通過RegExp類型支持正則表達式。
1.1 表示格式:
let expression = /pattern/flags;
//or
let expression = new RegExp("pattern str","flags")// pattern str 不需要由"/.../"包裹,
- pattern : 正則表達式;
- flags : 匹配模式的標記;
示例:
let expression = /[bc]at/i; //or let expression = new RegExp("[bc]at","i"); // 注意構造函數的兩個參數都是String, 且無需`/`包裹
注意: 在通過構造函數來創建一個Pattern 的時候,第一個參數,除了可以傳入String, 還能直接傳入一個已有的Pattern , 此時,構造函數的第二個參數,即Flags 將會覆蓋第一個參數中攜帶的flags。 利用這個特點,可以實現Pattern 的複製 和 flags 的修改, 以下是一個示例:
const exp1 = /cat/g; const exp2 = new RegExp(exp1,'i') // /cat/i
1.2 匹配模式:
“Gimyus”
- g : global , 全局匹配
- i : ignore , 大小寫忽略
- m : multiline , 多行匹配
- y : sticky 粘附模式,表示從lastIndex開始查找
- u : Unicode 模式, 啟用Unicode 匹配
- s : dotAll 模式,匹配任何字符(包括\n或\r)
全局匹配和多行匹配有什麼區別?
可以理解為,
/m
通常是和/g
一起使用以增強匹配模式。 以下是一個示例:hello my darling you are so sweat and hello my beauty hello my lady you are so kind hello my heartbeat you drum like a spring wind
- 匹配模式
/^hello/g
: 將會以整個字符串為匹配對象,僅僅匹配中字符串首部的單個「hello」 子字符串。- 匹配模式
/^hello/gm
:將會把每行自作單獨的匹配對象,將會匹配選中 1,4,6 行首的「hello」 子字符串,共三個。
unicode 模式,將會啟用Unicode 字符匹配的支持,以下是一個示例:
const sentence = 'A ticket to 大阪 costs ¥2000 👌.';
const regexpEmojiPresentation = /\p{Emoji_Presentation}/gu;
console.log(sentence.match(regexpEmojiPresentation));
// expected output: Array ["👌"]
dotAll 模式, 默認情況下,dot .
能夠匹配不包括 \n
(換行),\r
(光標回到行首),之外的任意字符。
當你所匹配的字符串中含有這兩個元字符時, 如果不開啟dotAll 模式,將不會被匹配到。 以下是一個示例:
MDN上有這樣一個demo:
var str1 = 'bar\nexample foo example';
var regex1 = new RegExp('bar.example','s');
console.log(regex1.dotAll); // Output: true
console.log(str1.replace(regex1,'')); // Output: foo example
var str2 = 'bar\nexample foo example';
var regex2 = new RegExp('bar.example');
console.log(regex2.dotAll); // Output: false
console.log(str2.replace(regex2,'')); // Output: bar
// example foo example
1.3 RegExp 實例屬性
gimyus 匹配模式是否開啟,除了在創建實例對象時去指定,還可以通過RegExp 實例的屬性訪問,並且可以設定值,但是注意,dotAll 匹配模式除外, 它是一個只讀屬性。 你只能在創建一個RegExp 實例的時候去設定好它。
如:
let exp0 = /[bc]at/s
//or
let exp1 = new RegExp("[bc]at","s")
//or 如果有需要,你也可以直接複製拓展一個已有的實例
let exp2 = /[bc]at/
let exp22 = new RegExp(exp2,"s")
除了這些boolean 類型的屬性,還有三個屬性,分別是:
source
: 正則表達式的字面量字符串;flags
: 正則表達式的模式標記字符串;lastIndex
: 整數類型,記錄了在源字符串中下一次搜索的起始位置(後面會講到)
let exp0 = /[bc]at/sgm;
console.log(exp0.source);//"[bc]at"
console.log(exp0.flags);//"gms"
1.4 RegExp 實例方法
1.4.1 exec()
1.4.1.1 基本用法
exec()
主要用於配合捕獲組使用, 只接收一個參數,即要匹配的目標字符串。如果沒有匹配則返回null
, 匹配則返回包含第一個匹配信息的數組。
RegExpPattern.exec("target string...")
⚠️ 注意: 該方法返回的數據類型雖然是一個數組, 但是它比較特殊, 它包含了兩個額外的屬性:
index
: 字符串中匹配模式的起始外置;input
:要查找的字符串;
數組的第一個元素是匹配整個模式的字符串, 其他的元素是與表達式中的捕獲組匹配的子字符串。 如果模式中並沒有捕獲組的花,那麼數組值包含一個元素。 以下是一些示例:
不包含捕獲組的情況
let str = "I always love the moment you smile";let exp = /love the moment/;let result = exp.exec(str);// result["love the moment"]
實際上,還有剛才說的幾個特殊屬性,如果你在console 台查看 result :
包含捕獲組的情況
let str = "I always love the moment you smile";let exp = /always (love (the moment (you)) smile)/;let result = exp.exec(str);// result[ "always love the moment you smile", "love the moment you smile", "the moment you", "you"]
1.4.1.2 exec()
和 \g
匹配模式
且看這樣一個示例:
當一個字符串中有多處被Pattern 所匹配時, 設定了/g
的匹配模式和 不設定時的結果存在差異。
即, 如果不設定\g
,那麼不論exec()
執行了多少次, 返回結果始終只會返回第一個匹配到的結果。 看起來,就像是,每次都是重新匹配, 且匹配到了一個結果之後就退出了 ,不做記錄。
而如果設定了/g
, 那麼就會每次執行將會返回一個新的匹配到的 子串結果, 直到沒有匹配項,返回null
為止, 看起來,就像是每次執行都記錄了下一次預將執行的索引值位置, 這個值實際上就是 RegExp的實例屬性lastIndex
注意,直接結果為null 之後,lastIndex 值被重新置0, 這意味着如果繼續執行exec()
方法,那麼會重新開始。
1.4.1.3 exec()
和 \y
黏着匹配模式
如果你仔細觀察\g
匹配模式,不難發現,該模式每次返回的lastindex
值 +1 後,就正好是下一個匹配字符的起始位置。 相當的「智能」。
\y
模式,則不同,它使得你在每次exec()
方法執行之前,都需要先明確下一個子串匹配的起始索引。並不會自動為你更新 lastIndex值為下一個匹配字符的正確位。
首次匹配,將從index = 0 的位置匹配,但是匹配不到所以返回null, 且永遠不會將lastIndex 設定為下一次正確匹配所在的位置, 但是可以手動指定正確的lastIndex 值,不過,這次匹配成功了,返回了正常的結果,而lastIndex 被刷新為了下一個非空字符所在的索引值, 依舊不會是下一次正確匹配的索引,如果想要能匹配到,還是要手動指定其索引值 – –
是不是很無語 – – , 我都知道了匹配項所在位置,我還tm需要用你來幹啥?
這個模式很少會用,可能某些特殊情況下才有用吧,例如遍歷字符串,其不斷刷新lastIndex值 ?或者知道了索引位去取對應的匹配項?
而
\g
匹配模式則完全不同, 每次匹配後都會刷新lastIndex 的值。
1.4.2 test()
Pattern.test("target string...")
test()
方法用於判斷某匹配Pattern 是否能夠匹配到目標內容。 返回一個布爾值。
示例 :
let str = "I always love the moment you smile";let exp = /love the moment/;exp.test(str); // truelet exp2 = /love the bala moment/;exp2.test(str); // false