W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
?y
? 修飾符讓我們能夠在源字符串中的指定位置進(jìn)行搜索。
為了掌握 y
修飾符的使用方式,讓我們來看一個(gè)實(shí)際的例子。
正則表達(dá)式的常見任務(wù)之一就是“詞法分析”:例如我們得到了一個(gè)代碼文本,我們需要找到它的結(jié)構(gòu)元素。例如,HTML 有標(biāo)簽和特性(attribute),JavaScript 代碼有函數(shù)、變量等。
編寫詞法分析器是一個(gè)特殊的領(lǐng)域,有自己的工具和算法,所以我們不做過多的深入,但有一個(gè)共同的任務(wù):在給定的位置讀取一些內(nèi)容。
例如,我們有一個(gè)代碼字符串 let varName = "value"
,我們需要從中讀取變量名,這個(gè)變量名從位置 4
開始。
我們將使用正則表達(dá)式 \w+
來查找變量名。實(shí)際上,JavaScript 的變量名需要更復(fù)雜的正則表達(dá)式才能準(zhǔn)確匹配,但在這里并不重要。
str.match(/\w+/)
將只會(huì)找到該行中的第一個(gè)單詞 (let
)。不是這個(gè)。g
。但是調(diào)用 str.match(/\w+/g)
會(huì)查找文本中的所有單詞,而我們需要位置 4
的一個(gè)單詞。同樣,不是我們需要的。
那么,如何在給定位置準(zhǔn)確搜索正則表達(dá)式?。
讓我們嘗試使用方法 regexp.exec(str)
。
對(duì)于沒有修飾符 g
和 y
的 regexp
,此方法僅查找第一個(gè)匹配項(xiàng),就像 str.match(regexp)
一樣。
……但是如果有修飾符 g
,那么它就會(huì)從存儲(chǔ)在 regexp.lastIndex
屬性中的位置開始在字符串 str
中進(jìn)行搜索。如果找到匹配項(xiàng),則將在匹配后立即將 regexp.lastIndex
設(shè)置為索引。
換句話說,regexp.lastIndex
作為搜索的起點(diǎn),每個(gè) regexp.exec(str)
調(diào)用都會(huì)將其重置為新值(“在最后一次匹配后”)。當(dāng)然,這只是在有 g
修飾符的情況下才會(huì)這樣。
因此,連續(xù)調(diào)用 regexp.exec(str)
會(huì)一個(gè)接一個(gè)地返回匹配。
以下是此類調(diào)用的示例:
let str = 'let varName'; // 讓我們找出字符串中的所有單詞
let regexp = /\w+/g;
alert(regexp.lastIndex); // 0 (初始值 lastIndex=0)
let word1 = regexp.exec(str);
alert(word1[0]); // let (第一個(gè)單詞)
alert(regexp.lastIndex); // 3 (匹配后的位置)
let word2 = regexp.exec(str);
alert(word2[0]); // varName (第二個(gè)單詞)
alert(regexp.lastIndex); // 11 (匹配后的位置)
let word3 = regexp.exec(str);
alert(word3); // null (沒有更多匹配項(xiàng))
alert(regexp.lastIndex); // 0 (搜索結(jié)束后重置索引)
我們可以通過循環(huán)獲取所有匹配。
let str = 'let varName';
let regexp = /\w+/g;
let result;
while (result = regexp.exec(str)) {
alert( `Found ${result[0]} at position ${result.index}` );
// 在位置 0 發(fā)現(xiàn)了 let,然后
// 在位置 4 發(fā)現(xiàn) varName
}
regexp.exec
的這種使用方式可以作為 str.matchAll
方法的替代,可以對(duì)匹配過程進(jìn)行更多控制。
讓我們回到我們的任務(wù)。
我們可以手動(dòng)將 lastIndex
設(shè)置為 4
,從給定的位置開始搜索!
像這樣:
let str = 'let varName = "value"';
let regexp = /\w+/g; // 沒有修飾符 "g",lastIndex 屬性會(huì)被忽略
regexp.lastIndex = 4;
let word = regexp.exec(str);
alert(word); // varName
哇塞!問題解決了!
我們從位置 regexp.lastIndex = 4
開始搜索 \w+
。
結(jié)果是正確的。
……但是等等,沒那么快。
請(qǐng)注意:regexp.exec
調(diào)用從位置 lastIndex
開始搜索,然后繼續(xù)搜索。如果 lastIndex
位置沒有單詞,但單詞在這之后的某個(gè)位置,那么單詞也會(huì)被找到:
let str = 'let varName = "value"';
let regexp = /\w+/g;
// 從位置 3 開始搜索
regexp.lastIndex = 3;
let word = regexp.exec(str);
// 在位置 4 找到匹配項(xiàng)
alert(word[0]); // varName
alert(word.index); // 4
對(duì)于某些任務(wù),包括詞法分析,這是錯(cuò)誤的。我們需要在文本的給定位置準(zhǔn)確地找到匹配,而不是在它之后的某個(gè)位置。這就是修飾符 “y” 的用途。
修飾符 y
使 regexp.exec
精確搜索位置 lastIndex
,而不是“從”它開始。
下面是帶有修飾符 y
的相同搜索:
let str = 'let varName = "value"';
let regexp = /\w+/y;
regexp.lastIndex = 3;
alert( regexp.exec(str) ); // null(位置 3 有一個(gè)空格,不是單詞)
regexp.lastIndex = 4;
alert( regexp.exec(str) ); // varName(在位置 4 的單詞)
正如我們所看到的,正則表達(dá)式 /\w+/y
在位置 3
處不匹配(不同于修飾符 g
),但在位置 4
處匹配。
這不僅是我們所需要的,當(dāng)使用修飾符 y
時(shí),還有一個(gè)重要的性能提升。
想象一下,我們有一個(gè)很長(zhǎng)的文本,其中根本沒有匹配項(xiàng)。然后使用修飾符 g
進(jìn)行搜索,會(huì)一直搜索到文本的末尾,并且什么也找不到,這將比使用修飾符 y
的搜索花費(fèi)更多的時(shí)間,后者只檢查確切的位置。
在像詞法分析這樣的任務(wù)中,通常會(huì)在一個(gè)確切的位置進(jìn)行多次搜索,以檢查我們?cè)谀抢镉惺裁?。使用修飾?nbsp;y
是正確實(shí)現(xiàn)和良好性能的關(guān)鍵。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: