1. 程式人生 > >RegExp在IE8等瀏覽器中的相容性問題

RegExp在IE8等瀏覽器中的相容性問題

這裡講的相容性問題主要指String的API在正則表示式的處理上不同。

匹配結果的相容性

第一個問題:在IE<=8中,如果split()方法的限定符是正則表示式,返回的陣列不包含空值元素,而如果限定符用字串表示則沒有這樣的問題:

",,ab,,".split(","); // output ["","","ab","",""]
",,ab,,".split(/,/); // output ["ab"]

第二個問題:正則表示式中可能有分組,但是這個分組可能並沒有參與(也就是沒有匹配到任何子字串)。關於這個分組的結果:IE<=8返回的不是undefined,而Firefox2會返回空字串,Safari3則直接什麼也不返回(結果導致陣列元素個數減少)。

"y".split(/(x)?y/); // ECMA :output ["",undefined,""]
"y".split(/(x)?y/); // IE8 :output []

如果是呼叫字串的match方法,返回的結果也不同:

"y".match(/(x)?y/); // ECMA :output ["y",undefined]
"y".match(/(x)?y/); // IE8 :output ["y", ""]

因此,替換的時候,返回的結果也不同:

// ECMA :output "undefined"
// IE8: output ""
"y".replace(/(x)?y/,function($0,$1){return String($1);};

關於lastIndex的幾個問題

0長度匹配時,lastIndex不變

先來看正常情況:如果執行帶/g的RegExp的exec或test方法,它會從RegExp的lastIndex位置開始搜尋。如果exec或test方法匹配到了,則更新RegExp的lastIndex索引為當前匹配的尾部。如果沒有找到,則重置lastIndex為0,同時返回null。

不正常情況:如果匹配的是空字元,也就是匹配長度為0,那麼lastIndex就永遠是0。其結果就是導致下面這段程式碼在大部分瀏覽器中陷入死迴圈。

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

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

// endPositions = [1,3,5] in IE <=8
// infinite loop in other browsers

為了避免死迴圈,IE<=8採用的方法是:即使匹配的長度為0,依然使lastIndex往後移。

解決死迴圈的方法一:

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

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

   endPositions.push(regex.lastIndex);

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

解決死迴圈方法二:使用String.prototype.replace方法。

因為在replace方法中可以輕鬆獲取匹配字串的長度和位置,所以可以根據這兩個資料算出lastIndex = indx + match.length。

執行replace方法,lastIndex可能會變

在IE<=8中,無論是非全域性匹配替換還是全域性匹配替換,lastIndex都會變,而且全域性匹配替換之後,lastIndex也沒有重置為0。而在Firefox,Chrome,IE>=9,Safari中,當replace方法執行全域性匹配替換和非全域性匹配替換時,lastIndex永遠是0。

IE<=8,執行String.prototype.replace方法之後,RegExp物件的lastIndex沒有重置為0。

var	regexp = /l/;
var text = "hello";

text.replace(regexp, function(match) {
	// output 3 in IE8
	console.log(regexp.lastIndex);
	return match;
});

console.log(regexp.lastIndex); // output 3 in IE8

在Firefox,Chrome,IE>=9,Safari中,當replace方法執行全域性匹配時,RegExp的lastIndex一直為0,而在IE<=8中lastIndex會變:

var regexp = /l/g;
var text = "hello";

text.replace(regexp, function(match) {
   console.log(regexp.lastIndex);// output 0
   return match;
});

console.log(regexp.lastIndex); // output 0 in FF,Chrome,IE>=9

關於[]和[^]

在IE<=8中,不允許出現[]或[^],這是因為IE<=8認為第一個右中括號(])屬於原義字元而不是一個和左中括號相匹配的特殊字元,除非[]中含有其他字元。

因此以下正則表示式在IE<=8都會報錯,錯誤資訊為"Expected ']' in regular expression"。

var regexp = /[]/;
var regexp = /[^]/;
var regexp = /a[^]/; 
var regexp = /a[]/;