JavaScriptでHtmlSpecialCharsと同等ですか?


167

どうやら、これは私が思っていたよりも見つけるのが難しいです。そしてそれはとても簡単です...

JavaScriptに組み込まれたPHPのhtmlspecialcharsに相当する関数はありますか?それを自分で実装するのはかなり簡単ですが、組み込み関数を使用できる場合はそれを使用する方が優れています。

PHPに慣れていない人のために、はhtmlspecialcharsは次のようなものを翻訳<htmltag/>&lt;htmltag/&gt;

私はそれを知ってescape()おり、encodeURI()このように動作しません。


phpには、var_dump、print_r、htmlspecialcharsなどの非常に優れたツールがいくつかあります。残念ながら、jsとは異なります。jsアラートはとても貧弱です。予期しない(およびアラートボックスに表示されない)文字列が来ていることをすばやく確認するには、文字列itslefではなく文字列の長さを警告します。
Melsi 14


参照stackoverflow.com/a/12034334/8804293を、それは偉大な答えがある
イライジャ・モック

回答:


330

ソリューションコードに問題があります-特殊文字の最初の出現のみをエスケープします。例えば:

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

正しく機能するコードは次のとおりです。

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

更新

次のコードは上記と同じ結果を生成しますが、特にテキストの大きなブロックでより良いパフォーマンスを発揮します(jbo5112に感謝)。

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

5
この関数のいいところは、デフォルトではdomがないnode.jsで機能することです
booyaa

6
単一の置換およびマッピング関数を使用する方が速く、単一の置換ははるかに優れています。(jsperf.com/escape-html-special-chars/11
jbo5112

1
@ jbo5112良い点は、JSが交換用のコールバックを許可していることに気付かなかったということです。このコードは理解しやすいですが、escapeHtml()から数ミリ秒を削ることが、何らかの理由で何百回も続けて呼び出さない限り、違いが出るとは思えません。
キップ

これにより、URLがテキストで変形され、Autolinker.jsなどのプラグインで使用できなくなります。これにアプローチする方法はありますか?
RadekMatěj2017

4
@RadekMatějその場合でも、HTMLドキュメントで使用する場合、両方のアンパサンドをエンコードすることは完全に有効です(私が主張するのが望ましいでしょう)。それでもプラグインのバグだと思います。
キップ

31

それがHTMLエンコーディングです。それを行うためのネイティブのjavascript関数はありませんが、グーグルしていくつかの機能をうまく実行できます。

例:http : //sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

編集:
これは私がテストしたものです:

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

出力: &lt;htmltag/&gt;


残念ながら、その場合はカスタム関数を使用する必要があります。
Bart van Heukelom、2009年

私の投稿に含まれているリンクでメソッドを試すことができます。確かにかなりきちんとしたコンセプト。
okw 2009年

@okw:わかりました、最初にこれにリンクしました:yuki-onna.co.uk/html/encode.htmlこれはencodeURIComponent、OPが要求したことを正確に実行し、まったく実行しません。編集してくれませんか?-1を元に戻せないようです。
クレセントフレッシュ

ええ、そのページのコードは論理的に見えますが、テストしていません。新しいリンクは機能しますが、自分で確認しました。しばらく前に投稿を更新しました。
okw 2009年

@BeauCielBleu:いいえ。作成されるノードは、単一のdiv要素とテキストノードのみです。テキスト `<img src = bogus onerror = alert(1337)>`でテキストノードを作成すると、img要素ではなくテキストノードのみが作成されます。
Tim Down

26

読む価値がある: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);
  };
})()

:これは一度だけ実行してください。そして、例えば、既にエンコードされた文字列でそれを実行しない&amp;となり&amp;amp;


3
これは、受け入れられ、最も投票された回答でなければなりません。なぜ投票がなかったのかわかりません。これは、jsperf(jsperf.com/escape-html-special-chars/11)での長い入力文字列(326KBのGoogle検索結果)と短い入力文字列の両方で、最速のベンチマークです。これに投票してください。
jbo5112 2014年

これと最高の票を得た答えの違いは何ですか?なぜ追加の内部関数ですか?説明はユーザーの理解を深めるのに役立ちます
Kosem

19

jQueryでは、次のようになります。

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

関連する質問からjQueryでHTML文字列をエスケープする

コメントで述べたように、この実装では二重引用符と単一引用符はそのまま残されます。つまり、要素属性を未加工のHTML文字列として作成する必要がある場合は、このソリューションを使用しないでください。


2
これにオーバーヘッドがある場合のアイデア-ダミーオブジェクトをDOMに追加しますか?
Kip

他に利点はありますか(たとえば、Unicode文字などがある場合)?
Kip

4
私がこれで見つけたもの:二重引用符と単一引用符はそのまま残されます。これを属性値で使用したい場合、これは問題になります。
Kip

1
小さなテキストのチャンクの場合、すべての置換を実行するのに30倍かかります。ただし、スケーリングは向上します。グーグルの検索結果ページ(326KB)と同じくらい巨大なもので、置換またはストレートなJavaScriptでこれを行うよりも25〜30%高速です。ただし、それらはすべて1つの置換とマッピング機能に一貫して負けます。
jbo5112 2014年

4
人々がこの答えに投票する方法:答えにはjquery:+1があります-一重引用符と二重引用符をエスケープしません:ummmm ..(scratching head).. +1。<!-- Caps rage begin --> この回答は、「HtmlSpecialCharsと同等」という質問の答えに近づくこともないため、負のスコアになるはずです。 <!-- Caps rage end -->it-does-not-escape-quotes-jesus-christ-and-other-神々。OMGあなたjquery人。
Sharky 2014年

19

HTMLをエスケープする関数は次のとおりです。

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

そしてデコードする:

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は、このための関数を提供します。

_.escape(string)

HTMLに挿入するために文字列をエスケープし、&、<、>、 "、および '文字を置き換えます。

http://underscorejs.org/#escape

これは組み込みのJavaScript関数ではありませんが、すでにUnderscoreを使用している場合は、変換する文字列が大きすぎない場合は、独自の関数を作成するよりも優れています。


5

これに関するさらに別の見方は、すべての文字マッピングを完全に無視し、代わりにすべての不要な文字をそれぞれの数字参照に変換することです。たとえば、次のようになります。

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

指定した正規表現が唯一のOPを脱出したかったが、HTMLが使用されようとしている、これらの文字が十分でないかもしれないエスケープという文脈に依存する特定の文字を処理します。Ryan Groveの記事HTMLエスケープには&、<、>、および "以外にも多くのトピックがあります。また、コンテキストによっては、XSSインジェクションを回避するために次のRegExが非常に必要になる場合があります。

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;");
    }

サンプル :

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

3

おそらく、そのような関数は必要ありません。コードはすでにブラウザーにあるため*、ブラウザーで逆方向にデコードして実際に使用する必要があるHTMLを生成してエンコードする代わりに、直接DOMにアクセスできます。

innerTextプロパティを使用すると、プレーンテキストをDOMに安全かつ迅速に挿入できます。提示されたエスケープ関数を使用するよりもはるかに高速です。静的な事前エンコードされた文字列をに割り当てるよりもさらに高速ですinnerHTML

classListクラスの編集、属性のdataset設定などに使用します。data-setAttribute

これらはすべてエスケープを処理します。より正確には、DOMのテキスト表現であるHTMLに取り組んでいるため、エスケープは不要であり、**の下でエンコードは実行されません。

// 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>

*この回答はサーバーサイドJavaScriptユーザー(Node.js など)を対象としたものではありません

**後で明示的に実際のHTMLに変換しない限り。たとえばアクセスすることによってinnerHTML-これは$('<div/>').text(value).html();、他の回答で提案された実行すると何が起こるかです。したがって、最終的な目標がドキュメントにデータを挿入することである場合、この方法でこれを行うと、作業が2回行われます。また、結果のHTMLではすべてがエンコードされているわけではなく、有効であるために必要な最小限のものだけがエンコードされていることがわかります。これはコンテキストに依存して行われます。そのため、このjQueryメソッドは引用符をエンコードしないため、汎用エスケープとして使用しないでください。属性の値の場所に信頼できないデータまたは引用符を含むデータを含む文字列としてHTMLを構築する場合は、引用符のエスケープが必要です。DOM APIを使用する場合は、エスケープを気にする必要はありません。


これをありがとう!私はそのような単純な解決策を長い間探し求めてきました。私が発見した一つの重要なことは、あなたのテキストに改行が含まれている場合、その後、あなたはHTMLの改行(のようなものに置き換えるのいずれかに持っているということですel.textContent = str; el.innerHTML = el.innerHTML.replace(/\n/g, '<br>'))、またはCSSの設定white-spaceにプロパティをprepre-wrap
stellatedHexahedron

@stellatedHexahedron、この問題を提起してくれてありがとう。のinnerText代わりに、推奨に回答を変更しましたtextContent。プロパティを読み取るときに少し遅くなり、他のいくつかの違いがあり<br>ますが、割り当て時に自動的に置き換えを行うという点で、より直感的です。
ユーザー

2

Node.JSユーザー(またはブラウザーでJadeランタイムを使用しているユーザー)には、Jadeのエスケープ機能を使用できます。

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

誰かがそれを維持しているなら、自分でそれを書く意味はありません。:)


1

okwの回答について少し詳しく説明します。

そのためにブラウザーのDOM関数を使用できます。

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

utils.escapeHTML('<escapeThis>&')

これは戻ります &lt;escapeThis&gt;&amp;

標準の関数createElementを使用して非表示の要素を作成し、関数textContentを使用して任意の文字列をコンテンツとして設定しinnerHTML、コンテンツをHTML表現で取得します。


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

これがそのパフォーマンスと最も重要なのは、.replace( '&'、 '&')。replace( '<'、 '<')...

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

反転したもの:

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

問題は、エンティティをデコードする方法を尋ねることではありません。これは、質問が求めていることの逆を行います。
クエンティン

これは、文字列のおよびの最初のインスタンスのみを置き換えます。&lt;&gr;
クエンティン

これは、(非Unicodeドキュメントの外で)エスケープする必要がある5つの文字のみをデコードし、エスケープされている可能性のある文字はデコードしません。
クエンティン

これは、セミコロンがオプションの場合のルールを考慮していません。
クエンティン

HTMLに次のように記述されている場合、代わりにTo write a greater than sign in HTML type &amp;gt;誤って表示されます>&gt;
Quentin

0

OWASPは、「[e]英数字を除い&#xHH;て、[an]属性からの切り替えを防ぐために、フォーマット(または使用可能な場合は名前付きエンティティ)で256未満のASCII値を持つすべての文字をエスケープすることをお勧めします。

それで、これを行う関数を使用例とともに示します。

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)+';')
}

このソリューションでは、文字の数値コードを使用<&#60;ます。たとえば、はに置き換えられます。

そのパフォーマンスは、マップを使用するソリューションよりも若干劣りますが、次のような利点があります。

  • ライブラリまたはDOMに依存しない
  • 覚えやすい(5つのHTMLエスケープ文字を覚える必要がない)
  • 小さなコード
  • かなり高速(5つの連鎖置換よりも高速です)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.