原生js實現replace方法

a2774206發表於2019-02-16

今天看到有人提問js的replace方法怎麼實現的,自己就試了試
js手冊裡的String物件的介紹replace大概是這樣:

 string.replace(regexp, replacement)

第一個引數:(regexp)

宣告瞭要替換的模式的RegExp物件。如果該引數是一個字串,則將它作為要檢索的直接量文字模式,而不是首先被轉換成RegExp物件。

第二個引數(replacement)

一個字串,宣告的是替換文字或生成替換文字的函式。詳見描述部分。

返回值

一個新字串,是用replacemenc替換了與regexp的第一次匹配或所有匹配之後得到的。

我就試著實現了下一開始思路沒考慮到正則,有很多問題,經過修改過的思路:

使用了正則的exec(),用split將匹配到的字串作為引數把原字串分割成若干陣列,然後將字串和替換的內容連線join起來就實現了

exec()將檢索字串string,從中得到與正規表示式regexp相匹配的文字。如果exec()找到了匹配的文字,它就會返回一個結果陣列。否則,返回null。

匹配到的第一個陣列[0]:匹配的文字,

第2個元素是與regexp的第二個子表示式相匹配的文字,以此類推。通常,陣列的length屬性宣告的是陣列中的元素個數。除了陣列元素和length屬性之外,exec()還返回兩個屬性。index屬性宣告的是匹配文字的第一個字元的位置。input屬性指的就是string。在呼叫非全域性RegExp物件的exec()方法時,返回的陣列與呼叫方法String.match()返回的方法相同。

String.prototype.replaces=function(reg,str){
    var arr = [];
    var newStr= this;
    var i= ``;
    //迴圈到 匹配不到替換的字串為止
    while(reg.exec(newStr)!=`null`) {
        /**使用try,catch是因為在迴圈到匹配到所有!=null下次循
        環reg.exec(newStr)[0]會報錯,迴圈完到報錯時直接return結果**/
        try{
            arr = newStr.split(reg.exec(newStr)[0]);
            newStr = arr.join(str);
            //如果該正則式子不是全域性正則(/g)不作迴圈直接修改一次返回
            if(!reg.global){
                return newStr;
            }
        }catch(e){
            return newStr;
        }
        
    }
    
} 

console.log("我是AbCd啊abcd啊abcd".replaces(/abcd/gi,`lipengpeng`))

----------------------------------------------------

經過測試,上面程式碼存在的問題如下:
當正規表示式是全域性時(/g)時,且只匹配到一個,會直接返回原字串,
在迴圈reg.exec(newStr)時,每次結果都不一樣,這裡暫時不清楚原因

修改後的:
String.prototype.replaces=function(reg,str){
    var arr = [];
    var newStr= this;
    var i= ``;
    var d;
    //為了防止reg.exec()每次結果不一樣,直接賦給一個變數
    //這裡注意給d=reg.exec()加括號, “=”的優先順序低
    while((d = reg.exec(newStr))!=null) {
        try{
            arr = newStr.split(d[0]);
            newStr = arr.join(str);
            if(reg.global){
                return newStr;
            }else{
                break;
            }
        }catch(e){
            console.log(e)
        }
        
    }
    
}

———————————分割線————————————-

以上程式碼繼續測試後,發現如果正則匹配到不區分大小寫(/i)且不開啟全域性匹配,結果會全域性替換。新增非全域性程式碼,不用管大小寫在全域性或非全域性(正則已經處理過),最終程式碼:

    String.prototype.replaces = function(reg, str) {
        var arr = [];
        var newStr = this;
        var i = ``;
        var d;
        while((d = reg.exec(newStr)) != null) {
            //debugger
            try {
                //console.log(d)
                if(reg.global) {
                    arr = newStr.split(d[0]);
                    newStr = arr.join(str);
                } else {
                    
                    var index = d[`index`];
                    var lastindex = (+index) + (+d[0].length);
                    var preStr = newStr.slice(0, index);
                    var nextStr = newStr.slice(lastindex);
                    newStr = preStr + str + nextStr;
                    break;

                }

            } catch(e) {
                console.log(e)
            }

        }
        return newStr

    }

    var s = "我是A,c,a,cc,c,c,cc,a".replaces(/a/ig, `b`)
    console.log(s)

相關文章