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[]/;