JavaScript >> Javascript 文檔 >  >> Tags >> regex

具有零長度正則表達式匹配的 IE lastIndex 錯誤

這篇博文的底線是 Internet Explorer 錯誤地增加了正則表達式對象的 08 成功的零長度匹配後的屬性。但是,對於不確定我在說什麼或對如何解決該問題感興趣的任何人,我將通過使用 10 方法。這是我最常遇到該錯誤的地方,我認為這將有助於解釋為什麼首先存在該問題。

首先,如果你還不熟悉如何使用 27 迭代一個字符串,你錯過了一些非常強大的功能。這是基本結構:

var	regex = /.../g,
	subject = "test",
	match = regex.exec(subject);

while (match != null) {
	// matched text: match[0]
	// match start: match.index
	// match end: regex.lastIndex
	// capturing group n: match[n]

	...

	match = regex.exec(subject);
}

37 為使用 44 的正則表達式調用方法 (全局)修飾符,它從正則表達式的 52 指定的主題字符串中的點開始搜索 屬性(最初為零,因此它從字符串的開頭開始搜索)。如果 67 方法找到匹配項,它會更新正則表達式的 71 屬性為匹配結束時的字符索引,並返回一個包含匹配文本和任何捕獲的子表達式的數組。如果從搜索開始的字符串中的點沒有匹配,83 重置為零,並且 96 被退回。

您可以通過移動 103 來收緊上面的代碼 方法調用到 116 循環的條件,像這樣:

var	regex = /.../g,
	subject = "test",
	match;

while (match = regex.exec(subject)) {
	...
}

這個更清潔的版本的工作原理與以前基本相同。只要 123 找不到任何進一步的匹配項,因此返回 134 ,循環結束。但是,使用此代碼的任一版本都需要注意幾個跨瀏覽器問題。一是如果正則表達式包含不參與匹配的捕獲組,則返回數組中的某些值可能是 149 或空字符串。我之前在一篇關於我所謂的非參與捕獲組的帖子中深入討論了這個問題。

另一個問題(this 的主題 post) 當您的正則表達式匹配一個空字符串時發生。您可能允許正則表達式這樣做的原因有很多,但如果您想不出任何原因,請考慮您接受來自外部來源的正則表達式的情況。這是這樣一個正則表達式的簡單示例:

var	regex = /^/gm,
	subject = "A\nB\nC",
	match,
	endPositions = [];

while (match = regex.exec(subject)) {
	endPositions.push(regex.lastIndex);
}

您可能期望 157 要設置為 166 的數組 ,因為這些是字符串開頭和每個換行符之後的字符位置。感謝175 修飾符,這些是正則表達式匹配的位置;由於正則表達式匹配空字符串,189 應該與 198 相同 .但是,Internet Explorer(使用 v5.5-7 測試)設置 202217 .其他瀏覽器會進入死循環,直到你把代碼短路。

那麼這裡發生了什麼?請記住,每次 221 運行時,它會嘗試從 232 指定的位置開始在主題字符串中進行匹配 正則表達式的屬性。由於我們的正則表達式匹配一個長度為零的字符串,242 仍然是我們開始搜索的地方。因此,每次循環我們的正則表達式都會匹配到相同的位置——字符串的開頭。 Internet Explorer 試圖通過自動遞增 254 來提供幫助並避免這種情況 當匹配一個零長度的字符串時。這似乎是個好主意(事實上,我看到人們堅決認為這是一個 Firefox 不會做同樣的錯誤),但這意味著在 Internet Explorer 中 265 不能依靠屬性來準確確定匹配的結束位置。

我們可以通過以下代碼跨瀏覽器糾正這種情況:

var	regex = /^/gm,
	subject = "A\nB\nC",
	match,
	endPositions = [];

while (match = regex.exec(subject)) {
	var zeroLengthMatch = !match[0].length;
	// Fix IE's incorrect lastIndex
	if (zeroLengthMatch && regex.lastIndex > match.index)
		regex.lastIndex--;

	endPositions.push(regex.lastIndex);

	// Avoid an infinite loop with zero-length matches
	if (zeroLengthMatch)
		regex.lastIndex++;
}

您可以在我不久前發布的跨瀏覽器拆分方法中看到上述代碼的示例。請記住,如果您的正則表達式可能無法匹配空字符串,則不需要此處的任何額外代碼。

處理此問題的另一種方法是使用 277 迭代主題字符串。 282 方法在零長度匹配後自動前進,完全避免了這個問題。不幸的是,在三大瀏覽器(IE、Firefox、Safari)中,292 似乎沒有處理 304 屬性,除了將其重置為零。 Opera 做對了(根據我對規範的閱讀)並更新了 316 一路上。鑑於目前的情況,你不能依賴 325 在您的代碼中使用 330 迭代字符串時 ,但您仍然可以輕鬆得出每個匹配結束時的值。舉個例子:

var	regex = /^/gm,
	subject = "A\nB\nC",
	endPositions = [];

subject.replace(regex, function (match) {
	// Not using a named argument for the index since capturing
	// groups can change its position in the list of arguments
	var	index = arguments[arguments.length - 2],
		lastIndex = index + match.length;

	endPositions.push(lastIndex);
});

這可能不像以前那麼清晰(因為我們實際上並沒有替換任何東西),但是你有它......兩種跨瀏覽器的方法來解決一個鮮為人知的問題,否則可能會在你的代碼中導致棘手的潛在錯誤。

Tutorial JavaScript 教程
  1. 在 Rails 中使用 Google 地圖

  2. 使用 React 構建卡片記憶遊戲

  3. Javascript 錯誤 Null 不是對象

  4. JavaScript 閉包教程 - 使用 JS 閉包示例代碼

  5. V8 發布 v7.8

  6. D3.js 漸變色圖表

  7. 開源分類:一種快速和現代的 classNames 替代方案

  1. 遞歸搜索全局變量及其屬性中的值

  2. 強烈推薦VScodes最大的擴展——我好像領悟了道理!

  3. 使用 HTML 和 JS 的驚人的清晰輸入

  4. EnterpriseJS 駛入舊金山

  5. Angular 14 單選按鈕教程和示例

  6. 如何使用 jQuery 製作一個簡單的淡入/淡出面板?

  7. 我應該使用什麼 JavaScript 庫來解析 URL 參數?

  1. 使用 Hooks 在 React/Gatsby 中構建一個 CRUD Firestore 應用程序

  2. 如何使用 Selenium 處理 CSS 中的偽元素?

  3. 6 個用於 Javascript 的機器學習庫

  4. 🎉 零配置 JS Confetti 庫