讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議37:推薦使用replace >

建議37:推薦使用replace

String對象的replace方法包含兩個參數,第一個參數表示執行匹配的正則表達式,也可以傳遞字符串,第二個參數表示準備代替匹配的子字符串,例如,把字符串html替換為htm。


var b=s.replace(\"html\",\"htm\");


與search和match方法不同,replace方法不會把字符串轉換為正則表達式對象,而是以字符串直接量的文本模式進行匹配。第二個參數可以是替換的文本,或者是生成替換文本的函數,把函數返回值作為替換文本來替換匹配文本。

replace方法同時執行查找和替換兩個操作。該方法將在字符串中查找與正則表達式相匹配的子字符串,然後調用第二個參數值或替換函數替換這些子字符串。如果正則表達式具有全局性質,那麼將替換所有的匹配子字符串,否則,只替換第一個匹配子字符串。

在replace方法中約定了一個特殊的字符「$」,如果這個美元符號附加了一個序號,就表示引用正則表達式中匹配的子表達式存儲的字符串。例如:


var s=\"javascript\";

var b=s.replace(/(java)(script)/,\"$2-$1\");

alert(b);//\"script-java\"


在上面的代碼中,正則表達式/(java)(script)/中包含兩對小括號,按順序排列,其中第一對小括號表示第一個子表達式,第二對小括號表示第二個子表達式,在replace方法的參數中可以分別使用字符串\"$1\"和\"$2\"來表示對它們匹配文本的引用,當然它們不是標識符,僅是一個標記,所以不可以作為變量參與計算。除了上面約定之外,美元符號與其他特殊字符組合還可以包含更多的語義,詳細說明如下:

❑$1、$2、…、$99:與正則表達式中的第1~99個子表達式相匹配的文本。

❑$&(美元符號+連字符):與正則表達式相匹配的子字符串。

❑$(美元符號+切換技能鍵):位於匹配子字符串左側的文本。

❑$\'(美元符號+單引號):位於匹配子字符串右側的文本。

❑$$:表示$符號。


var s=\"javascript\";

var b=s.replace(/.*/,\"$&$&\");//\"javascriptjavascript\"


由於字符串「$&」在replace方法中被約定為正則表達式所匹配的文本,因此利用它可以重複引用匹配的文本,從而實現字符串重複顯示效果。其中正則表達式「/.*/」表示完全匹配字符串。


var s=\"javascript\";

var b=s.replace(/script/,\"$&!=$\");//\"javascript!=java\"


其中字符「$&」代表匹配子字符串「script」,字符「$」代表匹配文本左側文本「java」。


var s=\"javascript\";

var b=s.replace(/java/,\"$&$\'is\");//\"javascript is script\"


其中字符「$&」代表匹配子字符串「java」,字符「$\'」代表匹配文本右側文本「script」。然後用「$&$\'is」所代表的字符串「javascript is」替換原字符串中的「java」子字符串,即組成一個新的字符串「javascript is script」。

在ECMAScript v3中明確規定,replace方法的第二個參數建議使用函數,而不是字符串(當然不是禁止使用),JavaScript 1.2實現了對這個特性的支持。這樣,當replace方法執行匹配時,每次都會調用該函數,函數的返回值將作為替換文本執行匹配操作,同時函數可以接收以$為前綴的特殊字符組合,用來對匹配文本的相關信息進行引用。


var s=\'script language=\"javascript\"type=\"text/javascript\"\';

var f=function($1){

return$1.substring(0,1).toUpperCase+$1.substring(1);

}

var a=s.replace(/(bw+b)/g,f);

alert(a);//Script Language=\"JavaScript\"Type=\"Text/JavaScript\"


在上面的示例代碼中,函數f的參數為特殊字符「$1」,它表示正則表達式/(bw+b)/中小括號每次匹配的文本。然後在函數體內對這個匹配文本進行處理,截取其首字母並轉換為大寫形式,之後返回新處理的字符串。replace方法能夠在原文本中使用這個返回的新字符串替換每次匹配的子字符串。

對於上面的示例,可以使用小括號來獲取更多匹配文本的信息。例如,直接利用小括號傳遞單詞的首字母,然後進行大小寫轉換處理:


var s=\'script language=\"javaScript\"type=\"text/javaScript\"\';

var f=function($1,$2,$3){

return$2.toUpperCase+$3;

}

var a=s.replace(/b(w)(w*)b/g,f);//Script Language=\"JavaScript\"Type=\"Text/JavaScript\"


在函數f中,第一個參數表示每次匹配的文本,第二個參數表示第一個小括號的子表達式所匹配的文本,即單詞的首字母,第二個參數表示第二個小括號的子表達式所匹配的文本。

實際上,replace方法的第二個參數(函數式參數)不需要傳遞任何形參,replace方法依然會向它傳遞多個實參,這些實參都包含一定的意思,具體說明如下:

❑第一個參數表示與匹配模式相匹配的文本,如上面示例中每次匹配的單詞字符串。

❑其後的參數是與匹配模式中子表達式相匹配的字符串,參數個數不限,根據子表達式數而定。

❑後面的參數是一個整數,表示匹配文本在字符串中的下標位置。

❑最後一個參數表示字符串自身。

例如,將上面示例中替換文本函數改為如下形式。


var f=function{

return arguments[1].toUpperCase+arguments[2];

}


如果不為函數傳遞形參,直接調用函數的arguments屬性,同樣能夠讀取到正則表達式中相關匹配文本的信息。

❑arguments[0]表示每次匹配的單詞。

❑arguments[1]表示第一個子表達式匹配的文本,即單詞的首字母。

❑arguments[2]表示第二個子表達式匹配的文本,即單詞的餘下字母。

❑arguments[3]表示匹配文本的下標位置,如第一個匹配單詞「script」的下標位置就是0,依此類推。

❑arguments[4]表示要執行匹配的字符串,這裡表示「script language=\"javascript\"type=\"text/javascript\"」。


var s=\'script language=\"javascript\"type=\"text/javascript\"\';

var f=function{

for(var i=0;i<arguments.length;i++){

alert(\"第\"+(i+1)+\"個參數的值:\"+arguments[i]);

}

}

var a=s.replace(/b(w)(w*)b/g,f);


在函數體中,使用for循環結構遍歷argumnets屬性,每次匹配單詞時,都會彈出5次提示信息,分別顯示上面所列的匹配文本信息。其中,arguments[1]、arguments[2]會根據每次匹配文本不同,分別顯示當前匹配文本中子表達式匹配的信息,arguments[3]顯示當前匹配單詞的下標位置。而arguments[0]總是顯示每次匹配的單詞,arguments[4]總是顯示被操作的字符串。

例如,下面代碼能夠自動提取字符串中的分數,進行匯總後算出平均分,然後利用replace方法提取每個分值,與平均分進行比較以決定替換文本的具體信息。


var s=\"張三56分,李四74分,王五92分,趙六84分\";

var a=s.match(/d+/g),sum=0;

for(var i=0;i<a.length;i++){

sum+=parseFloat(a[i]);

};

var avg=sum/a.length;

function f{

var n=parseFloat(arguments[1]);

return n+\"分\"+\"(\"+((n>avg)?(\"超出平均分\"+(n-avg)):(\"低於平均分\"+(avg-n)))+\"分)\";

}

var s1=s.replace(/(d+)分/g,f);

alert(s1);/*\"張三56分(低於平均分20.5分),李四74分(低於平均分2.5分),王五92分(超出平均分15.5分),趙六84分(超出平均分7.5分)\"*/


在上面的示例中,遍歷數組時不能夠使用for in語句,因為這個數組中還存儲著其他相關的匹配文本信息。應該使用for結構來實現。由於截取的數字都是字符串類型,所以應該把它們都轉換為數值類型,否則會被誤解,如把數字連接在一起,或者按字母順序進行比較等。