2015-09-27 54 views
4

在頁面我正在使我需要有一個特定大小的字符串環形緩衝區。我使用一個數組來實現這個目的,只需要推動和不移動。單個索引是單個字符。我不想使用一個字符串,因爲每次我將一個字符拖入緩衝區時都會發生複製。現在我需要在這個緩衝區上使用正則表達式。問題是,現在每次我想要匹配我需要array.join()這樣做是相當昂貴的...匹配正則表達式到字符數組

現在我想知道是否有可能直接在字符數組上使用正則表達式首先將其轉換爲字符串。

我想,如果有一個可變的字符串類型我永遠不會有這個問題...

+0

我想你可以在JS中實現自己的正則表達式引擎,但可能會比加入數組慢。 – Oriol

+0

爲什麼副本會變得重要? –

+0

@NiettheDarkAbsol因爲我需要每秒100000次操作。每次複製524288個字符是不可行的。 –

回答

1

同意..! JS字符串是不可變的,但是你的連接問題需要花費時間並不合理。我可以確認,在Chrome,Firefox,Opera,IE11和Safari上運行一個Array.prototype.join()的操作,通過一個包含1,000,000個隨機字符的陣列,需要10到40ms的時間,具體取決於引擎。是的...就是這樣。 (特別是蜘蛛猴閃耀)讓我們來看看

var arr = [], 
    match = [], 
    longStr = "", 
    count = 1000000, 
    start = 0, 
     end = 0; 

for (var i=0; i<count; i++){ 
    arr.push((+new Date()*Math.random()).toString(36)[0]); 
} 
start = performance.now(); 
longStr = arr.join(""); 
end = performance.now(); 
console.log("Concatenation took "+(end-start)+" msecs"); 
// Concatenation took 10.875 msecs.. Wow Firefox..! 
start = performance.now(); 
match = longStr.match(/7{5,}/g); 
!match && (match = []) 
end = performance.now(); 
console.log("Regex match took "+(end-start)+" msecs and found " +match.length+" matches as: ", match); 
//Regex match took 6.550000000046566 msecs and found 1 matches as: ["77777"] 

所以在執行了這些測試後,我決定嘗試回答你的問題。我們需要發明我們自己的可變字符串對象。實際上創建它非常簡單。一個具有特殊功能的異域數組對象,它也可以訪問Array.prototype函數。就像一個字符串對象,它將有一個額外的屬性,名爲primitiveValue,並且每次更新length屬性時,我們都將執行this.primitiveValue = this.join();操作,以便所有訪問length屬性的Array.prototype函數都會自動更新primitiveValue。如果我們編寫了繁重的工作流程,這會降低性能。好處是我們可以完全控制我們如何更新primitiveValue。如果我們喜歡,我們可以在每次對length屬性進行寫入訪問時跳過更新,並且可以在將正則表達式應用於字符串內容之前手動完成。或者我們甚至可以向RingBuffer.prototype和monkey patch添加正則表達式函數,將primitiveValue作業連接到它們。這裏有很多可能。

function RingBuffer(){ 
    this.primitiveValue = ""; 
    this.__len; 
    Object.defineProperty(this, "length", { 
              enumerable: true, 
              configurable: true, 
                get: this.getLength, 
                set: this.setLength 
              }); 
} 
RingBuffer.prototype = Array.prototype; 
RingBuffer.prototype.constructor = RingBuffer; 
RingBuffer.prototype.getLength = function(){ 
            return this.__len; 
           }; 
RingBuffer.prototype.setLength = function(val){ 
            this.__len = val; 
            this.primitiveValue = this.join(""); 
           }; 
var ringu = new RingBuffer(); 

所以我用100000個隨機字符填充了ringu。 Chrome 49的基準測試就是這樣;

var longStr = "", 
     count = 100000, 
     start = performance.now(), 
     end = 0; 
for (var i=1; i<=count; i++){ 
    ringu.push((+new Date()*Math.random()).toString(36)[0]); 
    if (!(i % 10000)){ 
    end = performance.now(); 
    console.log(i/10000+". 10000 pushes done at :"+(end - start)+" msecs"); 
    start = end; 
    } 
} 
console.log("ringu is filled with " + count + " random characters"); 
start = performance.now(); 
longStr = ringu.join(""); 
end = performance.now(); 
console.log("Last concatenation took "+(end-start)+" msecs"); 

1. 10000 pushes done at :1680.6399999996647 msecs 
2. 10000 pushes done at :4873.2599999997765 msecs 
3. 10000 pushes done at :8044.155000000261 msecs 
4. 10000 pushes done at :11585.525000000373 msecs 
5. 10000 pushes done at :14642.490000000224 msecs 
6. 10000 pushes done at :17998.389999999665 msecs 
7. 10000 pushes done at :20814.979999999516 msecs 
8. 10000 pushes done at :24024.445000000298 msecs 
9. 10000 pushes done at :27146.375 msecs 
10. 10000 pushes done at :30347.794999999925 msecs 
ringu is filled with 100000 random characters 
Last concatenation took 3.510000000707805 msecs 

所以,這取決於你如何經常做寫或多久你所需要的primitiveValue的級聯應用正則表達式,你可以在哪裏調用this.join("");指令決定之前。 500K項目RingBuffer的平均級聯時間將小於30ms。

那麼......這是SpiderMonkey的結果。因此,如果您要在Node.Js上運行類似的代碼,可以嘗試使用配有Spider Monkey或ChakraCore引擎的JXCore而不是使用V8的Node。

1. 10000 pushes done at :710.310000000005 msecs 
2. 10000 pushes done at :1831.4599999999991 msecs 
3. 10000 pushes done at :3018.199999999997 msecs 
4. 10000 pushes done at :4113.779999999999 msecs 
5. 10000 pushes done at :5144.470000000008 msecs 
6. 10000 pushes done at :6588.179999999993 msecs 
7. 10000 pushes done at :7860.005000000005 msecs 
8. 10000 pushes done at :8727.050000000003 msecs 
9. 10000 pushes done at :9795.709999999992 msecs 
10. 10000 pushes done at :10866.055000000008 msecs 
ringu is filled with 100000 random characters 
Last concatenation took 1.0999999999912689 msecs 
+0

驚人的,謝謝! –