Как избежать HTML - PullRequest
       21

Как избежать HTML

7 голосов
/ 15 июня 2010

У меня есть строка, которая содержит текст HTML.Мне нужно избегать только строк, а не тегов.Например, у меня есть строка, которая содержит

<ul class="main_nav">
<li>
<a class="className1" id="idValue1" tabindex="2">Test & Sample</a>
</li>
<li>
<a class="className2" id="idValue2" tabindex="2">Test & Sample2</a>
</li>
</ul>

Как экранировать только текст,

<ul class="main_nav">
<li>
<a class="className1" id="idValue1" tabindex="2">Test &amp; Sample</a>
</li>
<li>
<a class="className2" id="idValue2" tabindex="2">Test &amp; Sample2</a>
</li>
</ul>

без изменения тегов.

Может ли это бытьобрабатывается с помощью HTML DOM и JavaScript?

Спасибо

Ответы [ 5 ]

15 голосов
/ 28 марта 2014

Я очень удивлен, что никто не ответил на это. Вы можете просто использовать браузер самостоятельно, чтобы сделать побег за вас. Нет регулярных выражений лучше и безопаснее, чем позволить браузеру делать то, что он умеет лучше всего, обрабатывать HTML.

function escapeHTML(str){
    var p = document.createElement("p");
    p.appendChild(document.createTextNode(str));
    return p.innerHTML;
}

или короткая альтернатива с использованием Option () constructor

function escapeHTML(str){
    return new Option(str).innerHTML;
}
9 голосов
/ 15 июня 2010

(См. Ниже ответ на вопрос, который был обновлен в комментариях к OP ниже)

Может ли это быть обработано с помощью HTML DOM и javascript?

Нет, как только текст находится в DOM, концепция «экранирования» не применима.Исходный текст HTML необходимо экранировать, чтобы он правильно анализировался в DOM;когда он находится в DOM, ему не удается избежать.

Это может быть немного сложно понять, поэтому давайте рассмотрим пример.Вот некоторый HTML исходный текст (например, в HTML-файле, который вы просматриваете в браузере):

<div>This &amp; That</div>

После того, как браузер проанализирует DOM, текст внутриdiv равен This & That, потому что &amp; был интерпретирован в этот момент.

Так что вам нужно поймать это раньше, прежде чем браузер проанализирует текст в DOM.Вы не можете справиться с этим после факта, уже слишком поздно.

Отдельно строка, с которой вы начинаете, недействительна, если в ней есть такие вещи, как <div>This & That</div>.Предварительная обработка этой неверной строки будет сложной.Вы не можете просто использовать встроенные функции вашей среды (PHP или что-то еще, что вы используете на стороне сервера), потому что они также избегают тегов.Вам нужно будет выполнить обработку текста, извлекая только те части, которые вы хотите обработать, и затем запускать их через экранирующий процесс.Этот процесс будет сложным.&, за которым следует пробел, достаточно прост, но если в исходном тексте есть неэкранированные сущности, как вы узнаете, избегать их или нет?Предполагаете ли вы, что если строка содержит &amp;, вы оставляете ее в покое?Или превратить его в &amp;amp;?(Что совершенно верно; именно так вы показываете настоящую строку &amp; на HTML-странице.)

Что вам действительно нужно сделать, так это исправить основную проблему: создание этих недопустимых полукодированных строк.


Редактировать : из нашего потока комментариев ниже, вопрос полностью отличается от того, который показался в вашем примере (это не имеет критического значения).Чтобы подытожить комментарии для тех, кто приходит к этому свежему, вы сказали, что получаете эти строки из innerHTML WebKit, и я сказал, что это странно, innerHTML должен правильно кодировать & (и указал на aпара из тестовых страниц , которые предположили, что это так).Ваш ответ был:

Это работает для &.Но одна и та же тестовая страница не работает для сущностей, таких как ©, ®, "и многих других.

Это меняет природу вопроса. Вы хотите сделать сущности из символов, которые, в то же время, совершенно допустимыпри буквальном использовании (при условии, что у вас есть право кодирования текста), вместо этого может быть выражено как сущности и, следовательно, может быть более устойчивым к изменениям кодировки текста.

Мы можем это сделать. Согласно спецификации значения символов в строке JavaScript: UTF-16 (с использованием Unicode нормализованная форма C ) и любое преобразование из исходной кодировки символов ( ISO 8859-1 )., Windows-1252 , UTF-8 и т. Д.) Выполняется до того, как среда выполнения JavaScript увидит это (если вы не уверены на 100%, что вы понимаете, что я имею в виду под кодировкой символов, стоит остановиться сейчас,уходя и читая Абсолютный минимум каждый разработчик программного обеспечения Абсолютно, положительно должны знать о Unicode и наборы символов (без оправданий!) от Joel Spolsky, затем возвращаюсь.) Так что это входная сторона.На стороне вывода сущности HTML идентифицируют кодовые точки Unicode.Таким образом, мы можем надежно преобразовывать строки JavaScript в объекты HTML.

Дьявол кроется в деталях, как всегда.JavaScript явно предполагает, что каждое 16-битное значение является символом (см. Раздел 8.4 в спецификации), хотя это на самом деле не так для UTF-16 - одно 16-битное значение может быть «суррогатом» (таким как 0xD800), который толькоимеет смысл в сочетании со следующим значением, означающим, что два «символа» в строке JavaScript на самом деле являются одним символом.Это не редкость для дальневосточных языков.

Так что надежное преобразование, которое начинается со строки JavaScript и приводит к сущности HTML, не может предполагать, что «символ» JavaScript фактически равенсимвол в тексте, он должен обрабатывать суррогаты.К счастью, сделать это очень просто, потому что умные люди, определяющие Unicode, сделали его очень простым: первое суррогатное значение всегда находится в диапазоне 0xD800-0xDBFF (включительно), а второе суррогатное значение всегда находится в диапазоне 0xDC00-0xDFFF (включительно).Поэтому всякий раз, когда вы видите пару «символов» в строке JavaScript, которые соответствуют этим диапазонам, вы имеете дело с одним символом, определенным суррогатной парой.Формулы для преобразования из пары суррогатных значений в значение кодовой точки приведены в приведенных выше ссылках, хотя и довольно тупо;Я нахожу эту страницу гораздо более доступной.

Вооружившись всей этой информацией, мы можем написать функцию, которая будет принимать строку JavaScript и искать символы (реальные символы, которые могут быть однимили два «символа» длиной) вы можете превратить их в сущности, заменив их именованными сущностями на карте или числовыми сущностями, если их нет на нашей именованной карте:

// A map of the entities we want to handle.
// The numbers on the left are the Unicode code point values; their
// matching named entity strings are on the right.
var entityMap = {
    "160": "&nbsp;",
    "161": "&iexcl;",
    "162": "&#cent;",
    "163": "&#pound;",
    "164": "&#curren;",
    "165": "&#yen;",
    "166": "&#brvbar;",
    "167": "&#sect;",
    "168": "&#uml;",
    "169": "&copy;",
    // ...and lots and lots more, see http://www.w3.org/TR/REC-html40/sgml/entities.html
    "8364": "&euro;"    // Last one must not have a comma after it, IE doesn't like trailing commas
};

// The function to do the work.
// Accepts a string, returns a string with replacements made.
function prepEntities(str) {
    // The regular expression below uses an alternation to look for a surrogate pair _or_
    // a single character that we might want to make an entity out of. The first part of the
    // alternation (the [\uD800-\uDBFF][\uDC00-\uDFFF] before the |), you want to leave
    // alone, it searches for the surrogates. The second part of the alternation you can
    // adjust as you see fit, depending on how conservative you want to be. The example
    // below uses [\u0000-\u001f\u0080-\uFFFF], meaning that it will match and convert any
    // character with a value from 0 to 31 ("control characters") or above 127 -- e.g., if
    // it's not "printable ASCII" (in the old parlance), convert it. That's probably
    // overkill, but you said you wanted to make entities out of things, so... :-)
    return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0000-\u001f\u0080-\uFFFF]/g, function(match) {
        var high, low, charValue, rep

        // Get the character value, handling surrogate pairs
        if (match.length == 2) {
            // It's a surrogate pair, calculate the Unicode code point
            high = match.charCodeAt(0) - 0xD800;
            low  = match.charCodeAt(1) - 0xDC00;
            charValue = (high * 0x400) + low + 0x10000;
        }
        else {
            // Not a surrogate pair, the value *is* the Unicode code point
            charValue = match.charCodeAt(0);
        }

        // See if we have a mapping for it
        rep = entityMap[charValue];
        if (!rep) {
            // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
            rep = "&#" + charValue + ";";
        }

        // Return replacement
        return rep;
    });
}

хорошо, пропуская весь HTML через него, так как если эти символы появляются в значениях атрибутов, вы почти наверняка захотите также их там кодировать.Я действительно написал это для этого ответа, потому что проблема заинтриговала меня), и это полностью поставляется без какой-либо гарантии.Я пытался убедиться, что он обрабатывает суррогатные пары, потому что это необходимо для дальневосточных языков, и поддержка их - это то, что мы все должны делать сейчас, когда мир стал меньше.

Полная страница примера:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
</style>
<script type='text/javascript'>

// Make the function available as a global, but define it within a scoping
// function so we can have data (the `entityMap`) that only it has access to
var prepEntities = (function() {

    // A map of the entities we want to handle.
    // The numbers on the left are the Unicode code point values; their
    // matching named entity strings are on the right.
    var entityMap = {
        "160": "&nbsp;",
        "161": "&iexcl;",
        "162": "&#cent;",
        "163": "&#pound;",
        "164": "&#curren;",
        "165": "&#yen;",
        "166": "&#brvbar;",
        "167": "&#sect;",
        "168": "&#uml;",
        "169": "&copy;",
        // ...and lots and lots more, see http://www.w3.org/TR/REC-html40/sgml/entities.html
        "8364": "&euro;"    // Last one must not have a comma after it, IE doesn't like trailing commas
    };

    // The function to do the work.
    // Accepts a string, returns a string with replacements made.
    function prepEntities(str) {
        // The regular expression below uses an alternation to look for a surrogate pair _or_
        // a single character that we might want to make an entity out of. The first part of the
        // alternation (the [\uD800-\uDBFF][\uDC00-\uDFFF] before the |), you want to leave
        // alone, it searches for the surrogates. The second part of the alternation you can
        // adjust as you see fit, depending on how conservative you want to be. The example
        // below uses [\u0000-\u001f\u0080-\uFFFF], meaning that it will match and convert any
        // character with a value from 0 to 31 ("control characters") or above 127 -- e.g., if
        // it's not "printable ASCII" (in the old parlance), convert it. That's probably
        // overkill, but you said you wanted to make entities out of things, so... :-)
        return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0000-\u001f\u0080-\uFFFF]/g, function(match) {
            var high, low, charValue, rep

            // Get the character value, handling surrogate pairs
            if (match.length == 2) {
                // It's a surrogate pair, calculate the Unicode code point
                high = match.charCodeAt(0) - 0xD800;
                low  = match.charCodeAt(1) - 0xDC00;
                charValue = (high * 0x400) + low + 0x10000;
            }
            else {
                // Not a surrogate pair, the value *is* the Unicode code point
                charValue = match.charCodeAt(0);
            }

            // See if we have a mapping for it
            rep = entityMap[charValue];
            if (!rep) {
                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
                rep = "&#" + charValue + ";";
            }

            // Return replacement
            return rep;
        });
    }

    // Return the function reference out of the scoping function to publish it
    return prepEntities;
})();

function go() {
    var d = document.getElementById('d1');
    var s = d.innerHTML;
    alert("Before: " + s);
    s = prepEntities(s);
    alert("After: " + s);
}

</script>
</head>
<body>
<div id='d1'>Copyright: &copy; Yen: &yen; Cedilla: &cedil; Surrogate pair: &#65536;</div>
<input type='button' id='btnGo' value='Go' onclick="return go();">
</body>
</html>

Там я включил cedilla в качестве примера преобразования в числовую сущность, а не в именованную (поскольку я оставил cedil в моей очень маленькой примерной карте).И обратите внимание, что суррогатная пара в конце отображается в первом предупреждении как два «символа» из-за того, как JavaScript обрабатывает UTF-16.

0 голосов
/ 26 июля 2015

Вы можете закодировать все символы в вашей строке:

function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}

Или просто нацеливайтесь на главных героев, о которых нужно беспокоиться (&, inebreaks, <,>, "и '), например:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';

test.value=encode(myString);

testing.innerHTML=encode(myString);

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<p><b>What JavaScript Sees:</b></p>

<textarea id=test rows="3" cols="55"></textarea>

<p><b>What It Renders Too In HTML:</b></p>

<div id="testing">www.WHAK.com</div>
0 голосов
/ 15 июня 2010

Вы пробовали функцию escape () в Javascript? JavaScript escape () Функция

0 голосов
/ 15 июня 2010

Какой серверный язык вы используете?

Если вы используете PHP, вы можете использовать htmlentities

Пример:

<?php

$myHTML = "<h1>Some HTML Tags</h1><br />";
echo htmlentities($myHTML);

?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...