最近在做JS演算法項目時發現一個令我匪夷所思的問題, 這裡想記錄一下問題。 首先介紹一下字元串replace()方法的基本用法。 replace() 方法使用一個替換值(replacement)替換掉一個匹配模式(pattern)在原字元串中某些或所有的匹配項,並返回替換後的字元串。這個替換模式可以是 ...
最近在做JS演算法項目時發現一個令我匪夷所思的問題, 這裡想記錄一下問題。
首先介紹一下字元串replace()方法的基本用法。
replace() 方法使用一個替換值(replacement)替換掉一個匹配模式(pattern)在原字元串中某些或所有的匹配項,並返回替換後的字元串。這個替換模式可以是字元串或者RegExp
(正則表達式),替換值可以是一個字元串或者一個函數。
語法
str.replace(regexp|substr, newSubStr|function[, flags])
參數
regexp
- 一個
RegExp
對象。該正則所匹配的內容會被第二個參數的返回值替換掉。
substr
- 一個要被
newSubStr
替換的字元串。
newSubStr
- 替換掉第一個參數在原字元串中的匹配部分。該字元串中可以內插一些特殊的變數名。
function
一個用來創建新子字元串的函數,該函數的返回值將替換掉第一個參數匹配到的結果。該函數的參數描述請參考 指定一個函數作為參數 小節。
返回值
一個部分或全部匹配由替代模式所取代的新的字元串。
關於這個方法具體的信息參考MDN再好不過了。
String.prototype.replace() - JavaScript | MDN
現在有一個非常簡單的需求:將HTML代碼中的特殊字元進行實體轉義:
先看一個簡單的輸出沒有錯誤的版本:
正確方法一:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function
convertHTML(str) {
// :)
var
pattern=/[&<>
"']/g;
return str.replace(pattern,function(match){
switch(match){
case "
<
":
return "
<
";
case "
>
":
return "
>
";
case "
&
":
return "
&
";
case "
\
""
:
return
"""
;
case
"\'"
:
return
"'"
;
}
});
}
console.log(convertHTML(
"<Tom & Jerry>"
));//<Tom & Jerry>
指定一個函數作為第二個參數。在這種情況下,當匹配執行後, 該函數就會執行。 函數的返回值作為替換字元串。 (註意: 上面提到的特殊替換參數在這裡不能被使用。) 另外要註意的是, 如果第一個參數是正則表達式, 並且其為全局匹配模式, 那麼這個方法將被多次調用, 每次匹配都會被調用。
後來我對上述的代碼進行了改造,使代碼看起來更明瞭:
正確方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function convertHTML(str) {
// :)
var pattern=/[&<> "']/g;
rules={" & ":" & "," < ":" < "," > ":" > ",'" ':""","' ": "'" };
return str.replace(pattern, function (match){
return rules[match];
});
}
console.log(convertHTML( "<Tom & Jerry>" ));//<Tom & Jerry>
|
很明顯非常簡單的一個改造,我將規則鍵值對放在了rules對象中,輸出結果同樣也是正確的。
接下來,我發現貌似使用RegExp構造函數屬性還能使代碼變得更加簡單。RegExp構造函數屬性如下表所示:
其中一個叫做lastMatch的屬性深深吸引了我。我在想能不能像下麵這樣改造一下:
錯誤方法:
1 2 3 4 5 6 |
function convertHTML(str) {
var pattern=/[&<> "']/g;
rules={" & ":" & "," < ":" < "," > ":" > ",'" ':""","' ": "'" };
return str.replace(pattern,rules[RegExp.lastMatch]);
}
console.log(convertHTML( "<Tom & Jerry>" ));
|
寫完這個代碼,突然覺得自己聰明絕世,飄飄然了呢,然而一瓢冷水潑下來了。運行結果如下:
1 |
undefinedTom undefined Jerryundefined
|
這是什麼鬼,貌似該替換的字元都被替換成了undefined。接下來我加入了一條測試語句:
1 2 3 4 5 6 7 8 9 |
function convertHTML(str) {
// :)
var pattern=/[&<> "']/g;
rules={" & ":" & "," < ":" < "," > ":" > ",'" ':""","' ": "'" };
//下麵是測試代碼 console.log(RegExp.lastMatch); //>
return result;
}
console.log(convertHTML( "<Tom & Jerry>" ));
|
根據測試代碼,最後匹配的是“>”說明匹配是正確的,但是最後為什麼沒有按照規則進行替換呢,我想應該是replace()方法的實現機制我們沒有弄清楚,網上沒有找到相關的資料,所以只能提醒自己以後不能寫這樣的代碼了,在這種情況下,還是乖乖函數作為第二個參數。。。。。。等等,用函數做第二個參數,我又進行了下麵的修改:
1 2 3 4 5 6 7 8 9 10 |
function convertHTML(str) {
// :)
var pattern=/[&<> "']/g;
rules={" & ":" & "," < ":" < "," > ":" > ",'" ':""","' ": "'" };
var result=str.replace(pattern, function (){
return rules[RegExp.lastMatch]
});
return result;
}
console.log(convertHTML( "<Tom & Jerry>" )); //<Tom & Jerry>
|
註意上面我還是使用了正則表達式函數屬性與方法二是有區別的,但是結果卻是離奇的正確了。(難道閉包作怪)
replace()究竟隱藏著什麼秘密,還有待挖掘??
來自為知筆記(Wiz)