2013-07-03 31 views
10

我花了一段時間尋找最好的方式來逃避html字符串,並發現一些討論:discussion 1discussion 2。它引導我到replaceAll函數。然後我做了性能測試,並試圖找到解決方案實現了類似的速度,但沒有成功:(什麼是替換所有表現祕密? [HTML轉義]

這是我最後的test case set,我發現它的淨和我嘗試4例(在底部)擴大,但仍無法達到replaceAll() 。性能

什麼是祕密女巫使replaceAll()解決方案,以便快速

迎接

代碼片段:?!

String.prototype.replaceAll = function(str1, str2, ignore) 
{ 
    return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2); 
}; 

學分迄今qwerty

最快的情況下:

html.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll("'", '&#39;').replaceAll('<', '&lt;').replaceAll('>', '&gt;'); 
+1

許多內置方法在本機代碼和預先優化(正則表達式是一個)來實現,在模仿它們JavaScript以更快的方式顯然很難做到。 –

+0

肯定,但爲什麼「更換新RegExp」的情況是如此緩慢。它也使用RegExp。 – Saram

+0

仍然沒有正則表達式更換似乎更快http://jsperf.com/replaceallvssplitjoin –

回答

4

終於我找到了! 感謝Jack指着我對具體jsperf

我要指出,測試結果是陌生的;當在Benchmark.prototype.setup中定義的.replaceAll()爲 時,它的運行速度是全局(即在標籤內)定義的時間的兩倍。 我仍然不確定這是爲什麼,但它肯定必須與 有關,jsperf本身是如何工作的。

答案是:

replaceAll - 該河段jsperf限制/錯誤,由特殊序列"\\$&"引起的,所以結果是錯誤的。

compile() - 當無參數調用時,它將正則表達式定義更改爲/(?:)。我不知道它是錯誤還是什麼,但是在調用之後,性能結果很糟糕。

這是我的result safe tests

最後我準備了proper test cases

結果是,對於HTML逃避它使用本地基於DOM的解決方案,最喜歡的方式:

document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML 

,或者如果你重複了很多次,你可以一次準備變量做到這一點:

//prepare variables 
var DOMtext = document.createTextNode("test"); 
var DOMnative = document.createElement("span"); 
DOMnative.appendChild(DOMtext); 

//main work for each case 
function HTMLescape(html){ 
    DOMtext.nodeValue = html; 
    return DOMnative.innerHTML 
} 

謝謝大家的合作&發表評論和指示。

jsperf錯誤描述

作爲遵循的String.prototype.replaceAll定義:

function (str1, str2, ignore) { 
    return this.replace(new RegExp(str1.replace(repAll, "\\#{setup}"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$") : str2); 
} 
+1

你可以鏈接到jsperf錯誤? –

+0

@Jack當你開始任何錯誤測試(其中replace(All)在setup()過程中定義)轉到控制檯並顯示'String.prototype.replaceAll'的主體。我會做一些評論,在一分鐘內回答。 – Saram

-1

其實有更快的方法來做到這一點。

如果你可以做內聯分割和連接,你會得到更好的性能。

//example below 
var test = "This is a test string"; 
var test2 = test.split("a").join("A"); 

試試這個並運行性能測試。

+3

無法確認: http://jsperf.com/htmlencoderegex/31 – Saram

+0

檢查此http://dynamic-tools.net/toolbox/replaceAll/ – blganesh101

+0

使用replaceAll函數:** 0.054 **秒/ 使用replaceAll2函數:** 0.106 **秒/ 內嵌分割/加入:** 0.111 **秒/ 內嵌RegExp對象:** 0.182 **秒 內嵌RegExp對象無字符串:** 0.134 **秒 – Saram

2

至於性能也越高,我發現下面的功能是好得不能再好:

String.prototype.htmlEscape = function() { 
    var amp_re = /&/g, sq_re = /'/g, quot_re = /"/g, lt_re = /</g, gt_re = />/g; 

    return function() { 
     return this 
      .replace(amp_re, '&amp;') 
      .replace(sq_re, '&#39;') 
      .replace(quot_re, '&quot;') 
      .replace(lt_re, '&lt;') 
      .replace(gt_re, '&gt;'); 
    } 
}(); 

它初始化的正則表達式,並返回實際執行更換封閉。

Performance test

我要指出,測試結果是陌生的;當.replaceAll()被定義爲Benchmark.prototype.setup內時,其運行速度比全局定義時快(即在<script>標籤內)。我仍然不確定這是爲什麼,但它肯定必須與jsperf本身的工作方式有關。

使用RegExp.compile()

我想避免使用棄用的功能,主要是因爲這樣的表現應該由現代瀏覽器自動完成。這裏有一個帶有編譯表達式的版本:

String.prototype.htmlEscape2 = function() { 
    var amp_re = /&/g, sq_re = /'/g, quot_re = /"/g, lt_re = /</g, gt_re = />/g; 

    if (RegExp.prototype.compile) { 
     amp_re.compile(); 
     sq_re.compile(); 
     quot_re.compile(); 
     lt_re.compile(); 
     gt_re.compile(); 
    } 

    return function() { 
     return this 
      .replace(amp_re, '&amp;') 
      .replace(sq_re, '&#39;') 
      .replace(quot_re, '&quot;') 
      .replace(lt_re, '&lt;') 
      .replace(gt_re, '&gt;'); 
    } 
} 

這樣做會把所有其他東西都衝出水面!

Performance test

之所以.compile()給出這樣的性能提升,因爲當你編譯一個全球性的表達,例如/a/g它會被轉換爲/(?:)/(在Chrome上),這會導致它無用。

如果編譯無法完成,瀏覽器應該拋出一個錯誤而不是默默地銷燬它。

+0

請看@Joachim Isaksson評論如上。我認爲他找到了訣竅。 – Saram

+0

@Saram我沒有使用不合適的'.compile()'進行測試,但我懷疑這是一個有用的統計。測試基準中的某些東西正在影響結果。 –

+0

@Saram另外,根據[MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp),編譯了文字正則表達式*。 –