Javascript HtmlSpecialChars eşdeğeri?


167

Görünüşe göre, bu düşündüğümden daha zor. Ve hatta çok basit ...

Javascript içine yerleşik PHP'nin htmlspecialchars eşdeğer bir işlevi var mı? Bunu kendiniz uygulamanın oldukça kolay olduğunu biliyorum, ancak varsa yerleşik bir işlevi kullanmak sadece daha güzel.

PHP'ye aşina olmayanlar için htmlspecialchars <htmltag/>,&lt;htmltag/&gt;

Bunu biliyorum escape()ve encodeURI()bu şekilde çalışmaz.


php bazı gerçekten iyi araçlar var varddump, print_r, htmlspecialchars vb. Ne yazık ki js ile aynı olduğundan şüpheleniyorum. js uyarısı çok zayıf. Bazı beklenmedik (ve uyarı kutusunda görünmez) dizelerin geldiğini görmenin hızlı bir yolu, itslef dizesi yerine dize uzunluğunu uyarmaktır.
Melsi


Bkz. Stackoverflow.com/a/12034334/8804293 , harika bir cevabı var
Elijah Mock

Yanıtlar:


330

Çözüm kodunuzla ilgili bir sorun var - sadece her özel karakterin ilk oluşumundan kaçacak. Örneğin:

escapeHtml('Kip\'s <b>evil</b> "test" code\'s here');
Actual:   Kip&#039;s &lt;b&gt;evil</b> &quot;test" code's here
Expected: Kip&#039;s &lt;b&gt;evil&lt;/b&gt; &quot;test&quot; code&#039;s here

İşte düzgün çalışan kod:

function escapeHtml(text) {
  return text
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
}

Güncelleme

Aşağıdaki kod, yukarıdakilerle aynı sonuçları verecektir, ancak özellikle büyük metin bloklarında daha iyi performans gösterir (teşekkürler jbo5112 ).

function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}

5
Bu işlev hakkında güzel bir şey, varsayılan olarak bir dom olmayan node.js'de çalışmasıdır
booyaa

6
Tek bir değiştirme ve haritalama işlevi kullanmak daha hızlıdır ve tek değiştirme daha iyi ölçeklenir. ( jsperf.com/escape-html-special-chars/11 )
jbo5112

1
@ jbo5112 iyi bir nokta, JS değiştirme için geri çağrı izin farkında değildi. Bu kodu olsa anlamak daha kolay ve kaçış birkaç milisaniye kaçış escapeHtml () bir sebepten dolayı üst üste yüzlerce kez çağırmadıkça bir fark yaratacaktır şüpheliyim.
Kip

Bu, URL'leri metinde deforme eder ve bu da onları Autolinker.js gibi eklentiler için kullanılamaz hale getirir . Buna yaklaşmanın bir yolu var mı?
Radek Matěj

4
@ RadekMatěj Bu durumda bile, bir HTML belgesinde kullanıldığında her iki ve işaretin kodlanması mükemmel bir şekilde geçerlidir (tercih edilir. Hala eklenti ile bir hata olarak kabul ediyorum.
Kip

31

Bu HTML Kodlaması. Bunu yapmak için hiçbir yerel javascript işlevi yoktur, ancak google ve bazı güzel bitmiş olanlar alabilirsiniz.

Örneğin, http://sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

EDIT:
Ben test ettik budur:

var div = document.createElement('div');
  var text = document.createTextNode('<htmltag/>');
  div.appendChild(text);
  console.log(div.innerHTML);

Çıktı: &lt;htmltag/&gt;


Çok kötü, o zaman sadece özel bir işlev kullanmam gerekecek.
Bart van Heukelom

Yöntemi yazıma eklediğim bağlantıda deneyebilirsiniz. Gerçekten çok temiz bir kavram.
okw

@okw: Tamam, önce buna bağladınız : yuki-onna.co.uk/html/encode.html OP'nin tam olarak ne istediğini encodeURIComponentve ne yaptığını. Yani lütfen düzenleyebilir misiniz? -1'imi geri alamıyorum.
Crescent Fresh

Yah, bu sayfanın kodu mantıklı görünüyor ama test etmedim. Yeni bağlantı çalışıyor olsa da, kendim doğruladım. Yayını bir süre önce güncelledim.
okw

@BeauCielBleu: Hayır. Oluşturulan tek düğümler tek bir divöğe ve bir metin düğümüdür. `<İmg src = bogus onerror = alert (1337)>` metniyle bir metin düğümü oluşturmak, imgöğe değil yalnızca bir metin düğümü oluşturur .
Tim Down

26

Okumaya değer: http://bigdingus.com/2007/12/29/html-escaping-in-javascript/

escapeHTML: (function() {
 var MAP = {
   '&': '&amp;',
   '<': '&lt;',
   '>': '&gt;',
   '"': '&#34;',
   "'": '&#39;'
 };
  var repl = function(c) { return MAP[c]; };
  return function(s) {
    return s.replace(/[&<>'"]/g, repl);
  };
})()

Not : Bunu yalnızca bir kez çalıştırın. Ve mesela zaten kodlanmış dizeleri üzerinde çalışmaz &amp;hale gelir&amp;amp;


3
Bu kabul edilen ve en çok oy verilen cevap olmalıdır. Neden oyu olmadığından emin değilim. Bu, jsperf'de ( jsperf.com/escape-html-special-chars/11 ) hem uzun (326KB Google arama sonucu) hem de kısa giriş dizesi ile en hızlı karşılaştırma ölçütüdür . Lütfen oy verin.
jbo5112

En yüksek oyu alan cevap arasındaki fark nedir? Neden ek iç fonksiyon ?. Bir açıklama kullanıcıların daha iyi anlamalarına yardımcı olabilir
Kosem

19

JQuery ile şöyle olabilir:

var escapedValue = $('<div/>').text(value).html();

İlgili sorudan jQuery ile HTML dizelerinden kaçma

Yorumda belirtildiği gibi, çift tırnak ve tek tırnak bu uygulama için olduğu gibi bırakılmıştır. Ham html dizesi olarak element özniteliği yapmanız gerekiyorsa bu çözümün kullanılmaması gerektiği anlamına gelir.


2
herhangi bir fikrin varsa herhangi bir fikir - DOM kukla bir nesne ekleyerek?
Kip

ve başka avantajları var mı (örneğin, unicode karakterleriniz veya başka bir şey varsa)?
Kip

4
Bununla bulduğum bir şey: çift tırnak ve tek tırnak olduğu gibi kalır. Bir öznitelik değerinde kullanmak istiyorsanız, bu sorunlu hale getirir.
Kip

1
Küçük metin parçaları için bu, tüm yer değiştirmeleri çalıştırdığı sürece 30x sürer. Gerçi daha iyi ölçeklenir. Google arama sonucu sayfası (326KB) kadar devasa bir şeyle, yer değiştirmelerden% 25-30 daha hızlıdır veya bunu düz javascript'te yapar. Bununla birlikte, hepsi sürekli olarak tek bir değiştirme ve bir eşleme işlevine kaybeder.
jbo5112

4
insanlar bu cevaba nasıl oy veriyor: cevap jquery var: +1 - tek ve çift tırnak kaçmaz: ummmm .. (tırmalama kafa) .. +1. <!-- Caps rage begin --> "HtmlSpecialChars eşdeğeri" SORU CEVAP OLMADIĞI GİBİ ÇIKMADIĞI için bu cevabın NEGATİF puanı olmalıdır. <!-- Caps rage end -->o-does-not-kaçış-tırnak-İsa-Christ-ve-diğer-tanrıları. Aman tanrım, insanları jquery.
Sharky

19

İşte HTML'den kaçmak için bir fonksiyon:

function escapeHtml(str)
{
    var map =
    {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(m) {return map[m];});
}

Ve kod çözmek için:

function decodeHtml(str)
{
    var map =
    {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&#039;': "'"
    };
    return str.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/g, function(m) {return map[m];});
}

6

Underscore.js bunun için bir işlev sağlar:

_.escape(string)

HTML'ye eklemek, &, <,>, "ve 'karakterlerini değiştirmek için bir dizeden kaçar.

http://underscorejs.org/#escape

Bu yerleşik bir Javascript işlevi değildir, ancak zaten Underscore kullanıyorsanız, dönüştürülecek dizeleriniz çok büyük değilse kendi işlevinizi yazmaktan daha iyi bir alternatiftir.


5

Yine başka bir şey, tüm karakter eşlemesini tamamen bırakmak ve bunun yerine tüm istenmeyen karakterleri ilgili sayısal karakter referanslarına dönüştürmektir, örneğin:

function escapeHtml(raw) {
    return raw.replace(/[&<>"']/g, function onReplace(match) {
        return '&#' + match.charCodeAt(0) + ';';
    });
}

Not Belirtilen RegEx sadece OP HTML kullanılacak gidiyor kaçtığını bağlamına göre kaçmak istedi ama o belirli karakterleri işleme, bu karakterler yeterli olmayabilir. Ryan Grove'un makalesi HTML'den kaçmak için &, <,> ve " ifadelerinden daha fazlası var.

var regex = /[&<>"'` !@$%()=+{}[\]]/g

3
String.prototype.escapeHTML = function() {
        return this.replace(/&/g, "&amp;")
                   .replace(/</g, "&lt;")
                   .replace(/>/g, "&gt;")
                   .replace(/"/g, "&quot;")
                   .replace(/'/g, "&#039;");
    }

örneklem :

var toto = "test<br>";
alert(toto.escapeHTML());

3

Muhtemelen böyle bir işleve ihtiyacınız yoktur. Kodunuz zaten tarayıcıda * olduğundan, gerçekte kullanılacak tarayıcı tarafından geriye doğru deşifre edilmesi gereken HTML oluşturmak ve kodlamak yerine DOM'a doğrudan erişebilirsiniz.

innerTextDOM'a düz metin eklemek için, sunulan çıkış işlevlerinden herhangi birini kullanmaktan çok daha hızlı bir özellik kullanın . Statik bir preen kodlu dize atamaktan bile daha hızlıinnerHTML .

Kullanım classListdüzenleme sınıflarına, datasetseti için data-nitelikler vesetAttribute diğerleri için.

Bunların hepsi sizin için kaçmayı başaracak. Daha kesin olarak, kaçış gerekmez ve DOM'un metinsel temsili HTML üzerinde çalıştığınız için ** altında kodlama yapılmaz.

// use existing element
var author = 'John "Superman" Doe <john@example.com>';
var el = document.getElementById('first');
el.dataset.author = author;
el.textContent = 'Author: '+author;

// or create a new element
var a = document.createElement('a');
a.classList.add('important');
a.href = '/search?q=term+"exact"&n=50';
a.textContent = 'Search for "exact" term';
document.body.appendChild(a);

// actual HTML code
console.log(el.outerHTML);
console.log(a.outerHTML);
.important { color: red; }
<div id="first"></div>

* Bu yanıt, sunucu tarafı JavaScript kullanıcıları (Node.js vb.) İçin değildir. ) İçin değildir.

** Açıkça gerçek HTML'ye dönüştürmediğiniz sürece. Örneğin, erişerek innerHTML- $('<div/>').text(value).html();diğer yanıtlarda önerilen çalıştırdığınızda olan şey budur . Dolayısıyla nihai hedefiniz belgeye bazı veriler eklemekse, bunu yaparak işi iki kez yapacaksınız. Ayrıca, elde edilen HTML'de her şeyin kodlanmadığını, yalnızca geçerli olması için gereken minimum değeri görebilirsiniz. Bağlama bağlı olarak yapılır, bu nedenle bu jQuery yöntemi tırnak kodlaması yapmaz ve bu nedenle genel amaçlı bir escaper olarak kullanılmamalıdır. Bir özniteliğin değeri yerine güvenilmeyen veya tırnak işareti içeren veriler içeren bir dize olarak HTML oluştururken tırnaklardan kaçmak gerekir. DOM API'sini kullanırsanız, kaçmayı hiç önemsemeniz gerekmez.


Bunun için teşekkürler! Böylesine basit bir çözüm aramak için uzun zaman harcadım. Ben keşfettim önemli bir nokta metin yeni satır içeriyorsa, o zaman gerek ya HTML satır sonları ile bunların yerine (gibi bir şey olacaktır el.textContent = str; el.innerHTML = el.innerHTML.replace(/\n/g, '<br>')), ya da CSS ayarlamak white-spaceiçin özellik preveyapre-wrap
stellatedHexahedron

@stellatedHexahedron, bu sorunu gündeme getirdiğiniz için teşekkür ederiz. Bunun innerTextyerine önerim için cevabımı değiştirdim textContent. Biraz daha yavaş olsa da ve özelliği okurken bazı farklılıklar olsa da, <br>atandığında yedeklemeyi otomatik olarak yapması daha sezgiseldir .
kullanıcı

2

Node.JS kullanıcıları (veya tarayıcıda Jade çalışma zamanını kullanan kullanıcılar) için Jade'in kaçış işlevini kullanabilirsiniz.

require('jade').runtime.escape(...);

Başkasının bakımını üstlenmesi halinde kendiniz yazmanın bir anlamı yok. :)


1

Ben okw'un cevabına biraz ayrıntı veriyorum.

Bunun için tarayıcının DOM işlevlerini kullanabilirsiniz.

var utils = {
    dummy: document.createElement('div'),
    escapeHTML: function(s) {
        this.dummy.textContent = s
        return this.dummy.innerHTML
    }
}

utils.escapeHTML('<escapeThis>&')

Bu geri döner &lt;escapeThis&gt;&amp;

createElementGörünmez bir öğe oluşturmak için standart işlevi kullanır, daha sonra textContentherhangi bir dizeyi içerik olarak ayarlamak ve ardından innerHTMLiçeriği HTML temsiline almak için işlevi kullanır .


0
function htmlspecialchars(str) {
 if (typeof(str) == "string") {
  str = str.replace(/&/g, "&amp;"); /* must do &amp; first */
  str = str.replace(/"/g, "&quot;");
  str = str.replace(/'/g, "&#039;");
  str = str.replace(/</g, "&lt;");
  str = str.replace(/>/g, "&gt;");
  }
 return str;
 }

0

Umarım bu performansından dolayı yarışı kazanır ve en önemlisi .replace ('&', '&') kullanarak zincirleme bir mantık değil. Değiştir ('<', '<') ...

var mapObj = {
   '&':"&amp;",
   '<':"&lt;",
   '>':"&gt;",
   '"':"&quot;",
   '\'':"&#039;"
};
var re = new RegExp(Object.keys(mapObj).join("|"),"gi");

function escapeHtml(str) 
{   
    return str.replace(re, function(matched)
    {
        return mapObj[matched.toLowerCase()];
    });
}

console.log('<script type="text/javascript">alert('Hello World');</script>');
console.log(escapeHtml('<script type="text/javascript">alert('Hello World');</script>'));

0

Tersine çevrilmiş:

function decodeHtml(text) {
    return text
        .replace(/&amp;/g, '&')
        .replace(/&lt;/ , '<')
        .replace(/&gt;/, '>')
        .replace(/&quot;/g,'"')
        .replace(/&#039;/g,"'");
}

Soru, varlıkların kodunun nasıl çözüleceğini sormuyor. Bu, sorunun ne istediğinin tam tersini yapar.
Quentin

Bu, yalnızca bir dizenin ve dizenin ilk örneklerinin yerini alacaktır . &lt;&gr;
Quentin

Bu yalnızca beş karakter (Unicode olmayan belgelerin dışında) deşifre edecek gerekir öncelenmelidir, bu olanları deşifre olmayacak olabilir öncelenmelidir.
Quentin

Bu, noktalı virgülün isteğe bağlı olduğu zamandaki kuralları dikkate almaz.
Quentin

HTML diyorsa To write a greater than sign in HTML type &amp;gt;, bunun >yerine yanlış görüntülenecektir&gt;
Quentin

0

OWASP , alfasayısal karakterler için "[e] xcept, ASCII değerleri 256 olan tüm karakterlerden [&#xHH; değiştirilmesini önlemek için (veya varsa bir adlandırılmış varlıktan) ."

İşte bir kullanım örneği ile bunu yapan bir işlev:

function escapeHTML(unsafe) {
  return unsafe.replace(
    /[\u0000-\u002F]|[\u003A-\u0040]|[\u005B-\u00FF]/g,
    c => '&#' + ('000' + c.charCodeAt(0)).substr(-4, 4) + ';'
  )
}
document.querySelector('div').innerHTML =
  '<span class=' +
  escapeHTML('this should break it! " | / % * + , - / ; < = > ^') +
  '>' +
  escapeHTML('<script>alert("inspect the attributes")\u003C/script>') +
  '</span>'
<div></div>


-1
function htmlEscape(str){
    return str.replace(/[&<>'"]/g,x=>'&#'+x.charCodeAt(0)+';')
}

Örnek Bu çözüm, karakter sayısal kodu kullanır <ile değiştirilir&#60; .

Performansı bir harita kullanan çözümden biraz daha kötü olmasına rağmen , avantajları vardır:

  • Bir kitaplığa veya DOM'a bağlı değil
  • Hatırlaması oldukça kolay (5 HTML kaçış karakterini ezberlemenize gerek yok)
  • Küçük kod
  • Oldukça hızlı (5 zincirli yedek parçadan hala daha hızlı)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.