【小貼士】探一探javascript中的replace

葉小釵發表於2014-08-28

javascript字串與陣列有很多精巧的方法,比如splice、indexOf,而replace在字串處理中偶爾會產生讓人愉悅的效果

比如underscore中的模板引擎替換部分,又如信用卡分割的應用

簡單來說,replace用於將字串中一些字元替換為另一些字元,最簡單的情況如下

var num = '1234567890123456';
var numStr = '';
numStr = num.replace('1', 'a');
console.log(numStr);//a234567890123456

這個結果,事實上不太理想,因為他只替換了一個,後面的1沒有理我,於是這個時候正則便出現了

var num = '1234567890123456';
var numStr = '';
numStr = num.replace(/1/g, 'a');
console.log(numStr); //a234567890a23456

一個經典例子是,javascript實現的trim方法

String.prototype.trim = function () {
  return this.toString().replace(/(^\s*)|(\s*$)/g, '');
};
var str = ' sssssds  ';
alert('|' + str.trim() + '|'); //|sssssds|

正則出現的時候便會有一些比較特殊的標識“$”

字元替換文字
$1、$2、...、$99 與 regexp 中的第 1 到第 99 個子表示式相匹配的文字。
$& 與 regexp 相匹配的子串。
$` 位於匹配子串左側的文字。
$' 位於匹配子串右側的文字。
$$ 直接量符號。
var str = ' 123 ';
console.log(str.replace(/(^\s*)|(\s*$)/g, '-$&-')); //- -123- ---

一切都很美好的時候,不滿足的情況發生了,我們感覺這個結果與預期不符,具體原因我們後面再說,這裡先看看函式回撥情況

var str = ' 123 ';
var arr = [];
/*
引數一為匹配到的字串
引數二為子表示式中的資料對應( $i (i:1-99)),帶|號便會產生(注意這裡可能產生多個引數匹配)
引數三為匹配字串的匹配下標
最後一個參數列示字串本身
*/
console.log(str.replace(/(^\s*)|(\s*$)/g, function (match, $1, $2, offset) {
  console.log(arguments);
  arr.push('-' + (match || '') + '-');
  return '-' + (match || '') + '-';
}));
console.log(arr); //- -123- ---

以上其實想簡單說明下函式與$的關係,導致輸出的原因是因為正則沒有寫對:

var str = ' 123 ';
console.log(str.replace(/^(\s+)|(\s+)$/g, '-$&-')); 

PS:上面那個正則還是抄的,所以以後碰到類似問題還是得自己驗證才行啊

另外,我有一個信用卡賬號要做格式轉換:123456789012 => 1234 5678 9012

這個程式碼要用replace的話,不用函式便行不通的

一旦匹配成功,會替換為後面函式的的返回值,這個函式匹配成功幾次便會呼叫幾次,有些時候我們可以把它當做一個迴圈使用

var num = '123456789012';
var reg = /\d{4}/g;
var index = 0;
var arr = [];

num.replace(reg, function (match, offset) {
  arr.push(match);
});
console.log(arr.join(' ')); //1234 5678 9012 

最後我們來看看我們的underscore模板引擎語法,現在我們有一個模板字串,我們要將它轉換為一個函式,於是我們會這麼做

 1 var template = [
 2 '<ul class="ul-list" style="position: absolute; width: 100%; top: 0; left: 0;">',
 3   '<%for(var i = 0, len = data.length; i < len; i++) { %>',
 4   '<li data-key="<%=data[i].id %>" data-index="<%=i%>" <%if(data[i].disabled){ %> class="disabled"',
 5     '<%} %>>',
 6     '<%=data[i].name %></li>',
 7   '<%} %>',
 8 '</ul>',
 9 '<div class="cui-mask-gray">',
10 '</div>',
11 '<div class="cui-lines">',
12   '&nbsp;</div>'
13 ].join('');
14 
15 var escapes = {
16   "'": "'",
17   '\\': '\\',
18   '\r': 'r',
19   '\n': 'n',
20   '\t': 't',
21   '\u2028': 'u2028',
22   '\u2029': 'u2029'
23 };
24 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
25 
26 var index = 0;
27 var source = "__p+='";
28 var matcher = /(<%-[\s\S]+?)%>|<%=([\s\S]+?)%>|<%([\s\S]+?)%>|$/g;
29 
30 template.replace(matcher, function (match, escape, interpolate, evaluate, offset) {
31   source += template.slice(index, offset)
32         .replace(escaper, function (match) { return '\\' + escapes[match]; });
33 
34   if (escape) {
35     source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
36   }
37   if (interpolate) {
38     source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
39   }
40   if (evaluate) {
41     source += "';\n" + evaluate + "\n__p+='";
42   }
43   index = offset + match.length;
44   return match;
45 });
46 source += "';\n";
47 
48 source = 'with(obj||{}){\n' + source + '}\n';
49 
50 source = "var __t,__p='',__j=Array.prototype.join," +
51       "print=function(){__p+=__j.call(arguments,'');};\n" +
52       source + "return __p;\n";
53 
54 console.log(source);

上面的程式碼列印出的東西:

var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};
with(obj||{}){
__p+='<ul class="ul-list" style="position: absolute; width: 100%; top: 0; left: 0;">';
for(var i = 0, len = data.length; i < len; i++) { 
__p+='<li data-key="'+
((__t=(data[i].id ))==null?'':__t)+
'" data-index="'+
((__t=(i))==null?'':__t)+
'" ';
if(data[i].disabled){ 
__p+=' class="disabled"';
} 
__p+='>'+
((__t=(data[i].name ))==null?'':__t)+
'</li>';
} 
__p+='</ul><div class="cui-mask-gray"></div><div class="cui-lines">&nbsp;</div>';
}
return __p;

程式碼複雜度稍有提升,但是原理與上面一樣,各位自己讀下吧,今天的學習到此

相關文章