Убрать HTML из текстового JavaScript

Есть ли простой способ взять строку HTML в JavaScript и удалить HTML?

48 ответов

Решение

Если вы работаете в браузере, то самый простой способ - просто позволить браузеру сделать это за вас...

function strip(html)
{
   var tmp = document.createElement("DIV");
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}

Примечание: как отмечают люди в комментариях, этого лучше избегать, если вы не контролируете источник HTML (например, не запускайте его на чем-либо, что могло бы быть получено из пользовательского ввода). Для этих сценариев вы все равно можете позволить браузеру сделать всю работу за вас - см. Ответ Сабы об использовании теперь широко доступного DOMParser.

myString.replace(/<(?:.|\n)*?>/gm, '');

Я хотел бы поделиться отредактированной версией одобренного ответа Shog9.


Как отметил в своем комментарии Майк Сэмюэл, эта функция может выполнять встроенные коды JavaScript.
Но Shog9 прав, когда говорит "пусть браузер сделает это за вас..."

так.. вот моя отредактированная версия, используя DOMParser:

function strip(html){
   var doc = new DOMParser().parseFromString(html, 'text/html');
   return doc.body.textContent || "";
}

вот код для проверки встроенного JavaScript:

strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")

Кроме того, он не запрашивает ресурсы при разборе (например, изображения)

strip("Just text <img src='https://assets.rbl.ms/4155638/980x.jpg'>")

Самый простой способ:

jQuery(html).text();

Это получает весь текст из строки HTML.

В качестве расширения метода jQuery, если ваша строка может не соответствовать HTML (например, если вы пытаетесь удалить HTML из поля формы)

jQuery(html).text();

вернет пустую строку, если нет HTML

Использование:

jQuery('<p>' + html + '</p>').text();

вместо.

Обновление: как было указано в комментариях, в некоторых случаях это решение будет выполнять JavaScript, содержащийся в html если значение html может повлиять на злоумышленника, использовать другое решение.

Преобразование HTML для электронной почты в виде простого текста с сохранением гиперссылок (ссылка)

Вышеупомянутая функция, опубликованная Hypoxide, работает нормально, но я хотел кое-что, что в основном конвертировало бы HTML, созданный в редакторе Web RichText (например, FCKEditor), и очищало весь HTML, но оставляло все ссылки, потому что я хотел и HTML, и текстовая версия, помогающая создавать правильные части электронной почты STMP (как HTML, так и обычный текст).

После долгого поиска в Google я и мои коллеги придумали это с помощью движка регулярных выражений в Javascript:

str='this string has <i>html</i> code i want to <b>remove</b><br>Link Number 1 -><a href="http://www.bbc.co.uk">BBC</a> Link Number 1<br><p>Now back to normal text and stuff</p>
';
str=str.replace(/<br>/gi, "\n");
str=str.replace(/<p.*>/gi, "\n");
str=str.replace(/<a.*href="(.*?)".*>(.*?)<\/a>/gi, " $2 (Link->$1) ");
str=str.replace(/<(?:.|\s)*?>/g, "");

str переменная начинается так:

this string has <i>html</i> code i want to <b>remove</b><br>Link Number 1 -><a href="http://www.bbc.co.uk">BBC</a> Link Number 1<br><p>Now back to normal text and stuff</p>

и после запуска кода это выглядит так:

this string has html code i want to remove
Link Number 1 -> BBC (Link->http://www.bbc.co.uk)  Link Number 1


Now back to normal text and stuff

Как вы можете видеть, весь HTML был удален, а Ссылка с гиперссылкой была сохранена. Также я заменил <p> а также <br> теги с \n (символ новой строки), чтобы какое-то визуальное форматирование было сохранено.

Чтобы изменить формат ссылки (например, BBC (Link->http://www.bbc.co.uk)) просто отредактируйте $2 (Link->$1), где $1 это URL/URI href и $2 текст с гиперссылкой С ссылками непосредственно в текстовом виде большинство почтовых клиентов SMTP преобразуют их, чтобы пользователь мог щелкнуть по ним.

Надеюсь, вы найдете это полезным.

Улучшение принятого ответа.

function strip(html)
{
   var tmp = document.implementation.createHTMLDocument("New").body;
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}

Таким образом, что-то вроде этого не принесет вреда:

strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")

Firefox, Chromium и Explorer 9+ безопасны. Опера Престо по-прежнему уязвима. Также изображения, упомянутые в строках, не загружаются в Chromium и Firefox, сохраняя http-запросы.

Это должно делать работу в любой среде Javascript (включая NodeJS).text.replace(/<[^>]+>/g, '');

var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");

Это версия регулярного выражения, которая более устойчива к искаженному HTML, например:

Незакрытые теги

Some text <img

"<", ">" внутри атрибутов тега

Some text <img alt="x > y">

Newlines

Some <a href="http://google.com">

Код

var html = '<br>This <img alt="a>b" \r\n src="a_b.gif" />is > \nmy<>< > <a>"text"</a'
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");

Я изменил ответ Jibberboy2000, чтобы включить несколько <BR /> форматировать теги, удалить все внутри <SCRIPT> а также <STYLE> тегами, форматируйте полученный HTML, удаляя несколько разрывов строк и пробелов, и конвертируйте некоторый кодированный в HTML код в обычный. После некоторого тестирования выясняется, что вы можете преобразовать большинство полных веб-страниц в простой текст, в котором сохраняются заголовок и содержимое страницы.

В простом примере

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<!--comment-->

<head>

<title>This is my title</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style>

    body {margin-top: 15px;}
    a { color: #D80C1F; font-weight:bold; text-decoration:none; }

</style>
</head>

<body>
    <center>
        This string has <i>html</i> code i want to <b>remove</b><br>
        In this line <a href="http://www.bbc.co.uk">BBC</a> with link is mentioned.<br/>Now back to &quot;normal text&quot; and stuff using &lt;html encoding&gt;                 
    </center>
</body>
</html>

становится

Это мой титул

Эта строка имеет HTML-код, который я хочу удалить

В этой строке упоминается BBC ( http://www.bbc.co.uk/) со ссылкой.

Теперь вернемся к "обычному тексту" и прочему

Функция JavaScript и тестовая страница выглядят так:

function convertHtmlToText() {
    var inputText = document.getElementById("input").value;
    var returnText = "" + inputText;

    //-- remove BR tags and replace them with line break
    returnText=returnText.replace(/<br>/gi, "\n");
    returnText=returnText.replace(/<br\s\/>/gi, "\n");
    returnText=returnText.replace(/<br\/>/gi, "\n");

    //-- remove P and A tags but preserve what's inside of them
    returnText=returnText.replace(/<p.*>/gi, "\n");
    returnText=returnText.replace(/<a.*href="(.*?)".*>(.*?)<\/a>/gi, " $2 ($1)");

    //-- remove all inside SCRIPT and STYLE tags
    returnText=returnText.replace(/<script.*>[\w\W]{1,}(.*?)[\w\W]{1,}<\/script>/gi, "");
    returnText=returnText.replace(/<style.*>[\w\W]{1,}(.*?)[\w\W]{1,}<\/style>/gi, "");
    //-- remove all else
    returnText=returnText.replace(/<(?:.|\s)*?>/g, "");

    //-- get rid of more than 2 multiple line breaks:
    returnText=returnText.replace(/(?:(?:\r\n|\r|\n)\s*){2,}/gim, "\n\n");

    //-- get rid of more than 2 spaces:
    returnText = returnText.replace(/ +(?= )/g,'');

    //-- get rid of html-encoded characters:
    returnText=returnText.replace(/&nbsp;/gi," ");
    returnText=returnText.replace(/&amp;/gi,"&");
    returnText=returnText.replace(/&quot;/gi,'"');
    returnText=returnText.replace(/&lt;/gi,'<');
    returnText=returnText.replace(/&gt;/gi,'>');

    //-- return
    document.getElementById("output").value = returnText;
}

Он был использован с этим HTML:

<textarea id="input" style="width: 400px; height: 300px;"></textarea><br />
<button onclick="convertHtmlToText()">CONVERT</button><br />
<textarea id="output" style="width: 400px; height: 300px;"></textarea><br />

Из трюков CSS:

https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/

const originalString = `
  <div>
    <p>Hey that's <span>somthing</span></p>
  </div>
`;

const strippedString = originalString.replace(/(<([^>]+)>)/gi, "");

console.log(strippedString);

Другое, по общему признанию, менее изящное решение, чем у Никафа или Shog9, было бы рекурсивно обходить DOM, начиная с тега , и добавлять каждый текстовый узел.

var bodyContent = document.getElementsByTagName('body')[0];
var result = appendTextNodes(bodyContent);

function appendTextNodes(element) {
    var text = '';

    // Loop through the childNodes of the passed in element
    for (var i = 0, len = element.childNodes.length; i < len; i++) {
        // Get a reference to the current child
        var node = element.childNodes[i];
        // Append the node's value if it's a text node
        if (node.nodeType == 3) {
            text += node.nodeValue;
        }
        // Recurse through the node's children, if there are any
        if (node.childNodes.length > 0) {
            appendTextNodes(node);
        }
    }
    // Return the final result
    return text;
}

Если вы хотите сохранить ссылки и структуру содержимого (h1, h2 и т. Д.), Вам следует проверить TextVersionJS. Вы можете использовать его с любым HTML, хотя он был создан для преобразования электронного письма HTML в простой текст.

Использование очень просто. Например, в файле node.js:

var createTextVersion = require("textversionjs");
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";

var textVersion = createTextVersion(yourHtml);

Или в браузере с чистым js:

<script src="textversion.js"></script>
<script>
  var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
  var textVersion = createTextVersion(yourHtml);
</script>

Это также работает с require.js:

define(["textversionjs"], function(createTextVersion) {
  var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
  var textVersion = createTextVersion(yourHtml);
});

Также можно использовать фантастический HTML-парсер htmlparser2 pure JS. Вот рабочая демонстрация:

var htmlparser = require('htmlparser2');

var body = '<p><div>This is </div>a <span>simple </span> <img src="test"></img>example.</p>';

var result = [];

var parser = new htmlparser.Parser({
    ontext: function(text){
        result.push(text);
    }
}, {decodeEntities: true});

parser.write(body);
parser.end();

result.join('');

Выход будет This is a simple example.

Смотрите это в действии здесь: https://tonicdev.com/jfahrenkrug/extract-text-from-html

Это работает как в узле, так и в браузере, если вы упаковываете свое веб-приложение с помощью такого инструмента, как веб-пакет.

Для более простого решения попробуйте это => https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/

var StrippedString = OriginalString.replace(/(<([^>]+)>)/ig,"");

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

function removeTags(string, array){
  return array ? string.split("<").filter(function(val){ return f(array, val); }).map(function(val){ return f(array, val); }).join("") : string.split("<").map(function(d){ return d.split(">").pop(); }).join("");
  function f(array, value){
    return array.map(function(d){ return value.includes(d + ">"); }).indexOf(true) != -1 ? "<" + value : value.split(">")[1];
  }
}

var x = "<span><i>Hello</i> <b>world</b>!</span>";
console.log(removeTags(x)); // Hello world!
console.log(removeTags(x, ["span", "i"])); // <span><i>Hello</i> world!</span>

Я внес некоторые изменения в оригинальный скрипт Jibberboy2000. Надеюсь, он кому-нибудь пригодится

str = '**ANY HTML CONTENT HERE**';

str=str.replace(/<\s*br\/*>/gi, "\n");
str=str.replace(/<\s*a.*href="(.*?)".*>(.*?)<\/a>/gi, " $2 (Link->$1) ");
str=str.replace(/<\s*\/*.+?>/ig, "\n");
str=str.replace(/ {2,}/gi, " ");
str=str.replace(/\n+\s*/gi, "\n\n");

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

Я начал изучать, как php это делает, и наткнулся на библиотеку php.js, которая копирует метод strip_tags здесь: http://phpjs.org/functions/strip_tags/

function stripHTML(my_string){
    var charArr   = my_string.split(''),
        resultArr = [],
        htmlZone  = 0,
        quoteZone = 0;
    for( x=0; x < charArr.length; x++ ){
     switch( charArr[x] + htmlZone + quoteZone ){
       case "<00" : htmlZone  = 1;break;
       case ">10" : htmlZone  = 0;resultArr.push(' ');break;
       case '"10' : quoteZone = 1;break;
       case "'10" : quoteZone = 2;break;
       case '"11' : 
       case "'12" : quoteZone = 0;break;
       default    : if(!htmlZone){ resultArr.push(charArr[x]); }
     }
    }
    return resultArr.join('');
}

Счета для> внутренних атрибутов и <img onerror="javascript"> во вновь созданных элементах дом.

использование:

clean_string = stripHTML("string with <html> in it")

демо:

https://jsfiddle.net/gaby_de_wilde/pqayphzd/

демо топ-ответа, делающего ужасные вещи:

https://jsfiddle.net/gaby_de_wilde/6f0jymL6/1/

Очень хорошая библиотека была быsanitize-htmlкоторая является чистой функцией JavaScript и может помочь в любой среде.

Мой случай был на React Native, мне нужно было удалить все HTML-теги из заданных текстов. поэтому я создал эту функцию-оболочку:

      import sanitizer from 'sanitize-html';

const textSanitizer = (textWithHTML: string): string =>
  sanitizer(textWithHTML, {
    allowedTags: [],
  });

export default textSanitizer;

Теперь с помощью моегоtextSanitizer, я могу получить чистое текстовое содержимое.

Вы можете безопасно удалить HTML-теги, используя атрибут песочницы iframe.

Идея здесь в том, что вместо того, чтобы пытаться пересмотреть нашу строку, мы используем преимущества встроенного в браузер синтаксического анализатора, вставляя текст в элемент DOM и затем запрашивая textContent/innerText свойство этого элемента.

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

Недостатком этого подхода является то, что он работает только в браузерах.

Вот что я придумала (не проверено в бою):

const stripHtmlTags = (() => {
  const sandbox = document.createElement("iframe");
  sandbox.sandbox = "allow-same-origin"; // <--- This is the key
  sandbox.style.setProperty("display", "none", "important");

  // Inject the sanbox in the current document
  document.body.appendChild(sandbox);

  // Get the sandbox's context
  const sanboxContext = sandbox.contentWindow.document;

  return (untrustedString) => {
    if (typeof untrustedString !== "string") return ""; 

    // Write the untrusted string in the iframe's body
    sanboxContext.open();
    sanboxContext.write(untrustedString);
    sanboxContext.close();

    // Get the string without html
    return sanboxContext.body.textContent || sanboxContext.body.innerText || "";
  };
})();

Использование ( демо):

console.log(stripHtmlTags(`<img onerror='alert("could run arbitrary JS here")' src='bogus'>XSS injection :)`));
console.log(stripHtmlTags(`<script>alert("awdawd");</` + `script>Script tag injection :)`));
console.log(stripHtmlTags(`<strong>I am bold text</strong>`));
console.log(stripHtmlTags(`<html>I'm a HTML tag</html>`));
console.log(stripHtmlTags(`<body>I'm a body tag</body>`));
console.log(stripHtmlTags(`<head>I'm a head tag</head>`));
console.log(stripHtmlTags(null));

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

stringWithHTML = stringWithHTML.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, "");

Мне просто нужно было раздеть <a> теги и замените их текстом ссылки.

Кажется, это отлично работает.

htmlContent= htmlContent.replace(/<a.*href="(.*?)">/g, '');
htmlContent= htmlContent.replace(/<\/a>/g, '');

Вот версия, которая решает проблему безопасности @MikeSamuel:

function strip(html)
{
   try {
       var doc = document.implementation.createDocument('http://www.w3.org/1999/xhtml', 'html', null);
       doc.documentElement.innerHTML = html;
       return doc.documentElement.textContent||doc.documentElement.innerText;
   } catch(e) {
       return "";
   }
}

Обратите внимание, что он вернет пустую строку, если разметка HTML не является допустимым XML (иначе, теги должны быть закрыты, а атрибуты должны быть в кавычках). Это не идеально, но избегает проблемы использования потенциала безопасности.

Если вам не нужна действительная разметка XML, вы можете попробовать использовать:

var doc = document.implementation.createHTMLDocument("");

но это не идеальное решение и по другим причинам.

С помощью jQuery вы можете просто получить его, используя

$('#elementID').text()

Код ниже позволяет вам сохранить некоторые HTML-теги, удаляя все остальные

function strip_tags(input, allowed) {

  allowed = (((allowed || '') + '')
    .toLowerCase()
    .match(/<[a-z][a-z0-9]*>/g) || [])
    .join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)

  var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
      commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;

  return input.replace(commentsAndPhpTags, '')
      .replace(tags, function($0, $1) {
          return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
      });
}

Если вы не хотите создавать для этого DOM (возможно, вы не находитесь в контексте браузера), вы можете использовать пакет striptags npm.

      import striptags from 'striptags'; //ES6 <-- pick one
const striptags = require('striptags'); //ES5 <-- pick one

striptags('<p>An HTML string</p>');
      const strip=(text) =>{
    (new DOMParser()?.parseFromString(text,"text/html"))
    ?.body?.textContent
}

const value=document.getElementById("idOfEl").value

const cleanText=strip(value)

Принятый ответ работает в основном нормально, однако в IE, если html строка null вы получаете "null" (вместо ''). Исправлена:

function strip(html)
{
   if (html == null) return "";
   var tmp = document.createElement("DIV");
   tmp.innerHTML = html;
   return tmp.textContent || tmp.innerText || "";
}
Другие вопросы по тегам