Respostas:
Se você estiver executando em um navegador, a maneira mais fácil é permitir que o navegador faça isso por você ...
function stripHtml(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Nota: como as pessoas observaram nos comentários, é melhor evitar isso se você não controlar a fonte do HTML (por exemplo, não execute isso em nada que possa ter vindo da entrada do usuário). Para esses cenários, você ainda pode deixar o navegador fazer o trabalho por você - consulte a resposta da Saba sobre o uso do agora amplamente disponível DOMParser .
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
myString.replace(/<[^>]*>?/gm, '');
<img src=http://www.google.com.kh/images/srpr/nav_logo27.png onload="alert(42)"
se você estiver injetando via document.write
ou concatenando com uma string que contém a >
antes de injetar via innerHTML
.
>
restante será deixado no segundo. Isso não representa um risco de injeção. O risco ocorre devido à <
esquerda no primeiro, o que faz com que o analisador HTML esteja em um contexto diferente do estado dos dados quando o segundo é iniciado. Observe que não há transição do estado dos dados >
.
<button onClick="dostuff('>');"></button>
Assumindo HTML corretamente escrito, você ainda precisa levar em conta que um sinal maior que pode estar em algum lugar no texto citado em um atributo. Além disso, você deseja remover todo o texto dentro das <script>
tags, pelo menos.
Maneira mais simples:
jQuery(html).text();
Isso recupera todo o texto de uma string de html.
Eu gostaria de compartilhar uma versão editada da resposta aprovada do Shog9 .
Como Mike Samuel apontou com um comentário, essa função pode executar códigos javascript embutidos.
Mas Shog9 está certo ao dizer "deixe o navegador fazer isso por você ..."
então .. aqui minha versão editada, usando DOMParser :
function strip(html){
var doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || "";
}
aqui o código para testar o javascript embutido:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Além disso, ele não solicita recursos na análise (como imagens)
strip("Just text <img src='https://assets.rbl.ms/4155638/980x.jpg'>")
Como uma extensão do método jQuery, se a sua string não puder conter HTML (por exemplo, se você estiver tentando remover HTML de um campo de formulário)
jQuery(html).text();`
retornará uma string vazia se não houver HTML
Usar:
jQuery('<p>' + html + '</p>').text();
em vez de.
Atualização:
Como foi indicado nos comentários, em algumas circunstâncias esta solução executará javascript contido html
se o valor de html
puder ser influenciado por um invasor, use uma solução diferente.
$("<p>").html(html).text();
jQuery('<span>Text :) <img src="a" onerror="alert(1)"></span>').text()
A função acima postada pelo hipóxido funciona bem, mas eu estava atrás de algo que basicamente convertia o HTML criado em um editor Web RichText (por exemplo, FCKEditor) e limpava todo o HTML, mas deixava todos os links devido ao fato de que eu queria tanto o HTML quanto o HTML. a versão em texto sem formatação para ajudar a criar as partes corretas para um email do STMP (HTML e texto sem formatação).
Depois de muito tempo pesquisando no Google, eu e meus colegas descobrimos isso usando o mecanismo de expressão regular em 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, "");
a str
variável começa assim:
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>
e depois que o código foi executado, fica assim: -
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
Como você pode ver, todo o HTML foi removido e o Link foi mantido com o texto com hiperlink ainda intacto. Também substituí as tags <p>
e <br>
por \n
(newline char) para que algum tipo de formatação visual seja mantida.
Para alterar o formato do link (por exemplo BBC (Link->http://www.bbc.co.uk)
), basta editar o $2 (Link->$1)
, onde $1
está o URL / URI href e o $2
texto com hiperlink. Com os links diretamente no corpo do texto sem formatação, a maioria dos clientes de email SMTP os converte para que o usuário possa clicar neles.
Espero que você ache isso útil.
Uma melhoria na resposta aceita.
function strip(html)
{
var tmp = document.implementation.createHTMLDocument("New").body;
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Dessa forma, algo funcionando assim não fará mal:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Firefox, Chromium e Explorer 9+ são seguros. O Opera Presto ainda é vulnerável. As imagens mencionadas nas seqüências também não são baixadas no Chromium e Firefox, salvando solicitações http.
<script><script>alert();
Isso deve funcionar em qualquer ambiente Javascript (NodeJS incluído).
const text = `
<html lang="en">
<head>
<style type="text/css">*{color:red}</style>
<script>alert('hello')</script>
</head>
<body><b>This is some text</b><br/><body>
</html>`;
// Remove style tags and content
text.replace(/<style[^>]*>.*<\/style>/gm, '')
// Remove script tags and content
.replace(/<script[^>]*>.*<\/script>/gm, '')
// Remove all opening, closing and orphan HTML tags
.replace(/<[^>]+>/gm, '')
// Remove leading spaces and repeated CR/LF
.replace(/([\r\n]+ +)+/gm, '');
<html><style..>* {font-family:comic-sans;}</style>Some Text</html>
Eu alterei a resposta de Jibberboy2000 para incluir vários <BR />
formatos de tag, remova tudo dentro <SCRIPT>
e <STYLE>
etiquetas, formatar o HTML resultante, removendo várias quebras de linha e espaços e converter alguns códigos HTML-codificado em normal. Após alguns testes, parece que você pode converter a maioria das páginas da Web completas em texto simples, onde o título e o conteúdo da página são mantidos.
No exemplo simples,
<!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 "normal text" and stuff using <html encoding>
</center>
</body>
</html>
torna-se
Este é o meu título
Esta cadeia tem código html que eu quero remover
Nesta linha é mencionada a BBC ( http://www.bbc.co.uk ) com link.
Agora, de volta ao "texto normal" e outras coisas usando
A função JavaScript e a página de teste têm esta aparência:
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(/ /gi," ");
returnText=returnText.replace(/&/gi,"&");
returnText=returnText.replace(/"/gi,'"');
returnText=returnText.replace(/</gi,'<');
returnText=returnText.replace(/>/gi,'>');
//-- return
document.getElementById("output").value = returnText;
}
Foi usado com este 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 />
/<p.*>/gi
deveria ser /<p.*?>/gi
.
<br>
tags que você poderia usar uma boa expressão regular em vez disso: /<br\s*\/?>/
de que maneira você tem apenas uma substituição em vez de 3. Além disso, parece-me que, exceto para a decodificação de entidades que você pode ter um único regex, algo como isto: /<[a-z].*?\/?>/
.
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Esta é uma versão regex, que é mais resistente a HTML malformado, como:
Tags não fechadas
Some text <img
"<", ">" dentro dos atributos da tag
Some text <img alt="x > y">
Novas linhas
Some <a
href="http://google.com">
O código
var html = '<br>This <img alt="a>b" \r\n src="a_b.gif" />is > \nmy<>< > <a>"text"</a'
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Outra solução, reconhecidamente menos elegante que a do nickf ou do Shog9, seria percorrer recursivamente o DOM começando na tag <body> e anexando cada nó de texto.
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;
}
Se você deseja manter os links e a estrutura do conteúdo (h1, h2, etc), verifique TextVersionJS Você pode usá-lo com qualquer HTML, embora tenha sido criado para converter um email em HTML em texto sem formatação.
O uso é muito simples. Por exemplo em node.js:
var createTextVersion = require("textversionjs");
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
var textVersion = createTextVersion(yourHtml);
Ou no navegador com js puro:
<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>
Também funciona com o require.js:
define(["textversionjs"], function(createTextVersion) {
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
var textVersion = createTextVersion(yourHtml);
});
Depois de tentar todas as respostas mais mencionadas, se não todas, elas tiveram casos extremos e não conseguiram atender completamente minhas necessidades.
Comecei a explorar como o php faz isso e me deparei com a lib php.js, que replica o método strip_tags aqui: http://phpjs.org/functions/strip_tags/
allowed == ''
que eu acho que é o que o OP pediu, que é quase o que Byron respondeu abaixo (Byron só tem o [^>]
errado.)
allowed
param você está vulnerável a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
retornos<p onclick="alert(1)">mytext</p>
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('');
}
É responsável por> atributos internos e <img onerror="javascript">
por elementos dom recém-criados.
uso:
clean_string = stripHTML("string with <html> in it")
demo:
https://jsfiddle.net/gaby_de_wilde/pqayphzd/
demonstração da resposta principal fazendo as coisas terríveis:
string with <a malicious="attribute \">this text should be removed, but is not">example</a>
).
Muitas pessoas já responderam isso, mas achei que seria útil compartilhar a função que escrevi que retira as tags HTML de uma string, mas permite incluir uma matriz de tags que você não deseja remover. É bem curto e tem funcionado muito bem para mim.
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>
Eu acho que a maneira mais fácil é usar expressões regulares como alguém mencionado acima. Embora não haja motivo para usar um monte deles. Tentar:
stringWithHTML = stringWithHTML.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, "");
[^<>]
com [^>]
porque uma tag válida não pode incluir um <
caractere e a vulnerabilidade XSS desaparece.
Fiz algumas modificações no script Jibberboy2000 original Espero que seja útil para alguém
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");
Aqui está uma versão que aborda as preocupações de segurança de @ 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 "";
}
}
Observe que ele retornará uma string vazia se a marcação HTML não for XML válido (ou seja, as tags devem ser fechadas e os atributos devem ser citados). Isso não é o ideal, mas evita a questão de ter o potencial de explorar a segurança.
Se não é necessário ter uma marcação XML válida, você pode tentar usar:
var doc = document.implementation.createHTMLDocument("");
mas essa não é uma solução perfeita por outras razões.
Você pode remover com segurança as tags html usando o atributo sandbox iframe .
A idéia aqui é que, em vez de tentar regexar nossa string, aproveitamos o analisador nativo do navegador injetando o texto em um elemento DOM e consultando a propriedade textContent
/ innerText
desse elemento.
O elemento mais adequado para injetar nosso texto é um iframe em área restrita, para impedir qualquer execução arbitrária de código (também conhecido como XSS ).
A desvantagem dessa abordagem é que ela só funciona em navegadores.
Aqui está o que eu criei (Não testado em batalha):
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 || "";
};
})();
Uso ( demo ):
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));
let
e const
. Além disso, usando sua solução, tenho muitas referências de iframes
não usadas dentro do documento. Considere adicionar um document.body.removeChild(sandbox)
no código para futuros leitores baseados em pasta de cópia.
O código abaixo permite que você retenha algumas tags html enquanto remove todas as outras
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 : '';
});
}
phpjs
). Se você usar o allowed
param você está vulnerável a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
retornos<p onclick="alert(1)">mytext</p>
Também é possível usar o fantástico analisador HTML HTML puro htmlparser2 . Aqui está uma demonstração de trabalho:
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('');
A saída será This is a simple example.
Veja em ação aqui: https://tonicdev.com/jfahrenkrug/extract-text-from-html
Isso funciona no nó e no navegador se você compactar seu aplicativo da Web usando uma ferramenta como o webpack.
Eu só precisava tirar o <a>
tags e substituí-las pelo texto do link.
Isso parece funcionar muito bem.
htmlContent= htmlContent.replace(/<a.*href="(.*?)">/g, '');
htmlContent= htmlContent.replace(/<\/a>/g, '');
title="..."
.
Para uma solução mais fácil, tente isso => https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
var StrippedString = OriginalString.replace(/(<([^>]+)>)/ig,"");
jquery simples de 2 linhas para remover o html.
var content = "<p>checking the html source </p><p>
</p><p>with </p><p>all</p><p>the html </p><p>content</p>";
var text = $(content).text();//It gets you the plain text
console.log(text);//check the data in your console
cj("#text_area_id").val(text);//set your content to text area using text_area_id
A resposta aceita funciona bem principalmente, no entanto, no IE, se a html
string é a que null
você obtém "null"
(em vez de ''). Fixo:
function strip(html)
{
if (html == null) return "";
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
input
O elemento suporta apenas um texto de linha :
O estado do texto representa um controle de edição de texto simples de uma linha para o valor do elemento.
function stripHtml(str) {
var tmp = document.createElement('input');
tmp.value = str;
return tmp.value;
}
Atualização: isso funciona conforme o esperado
function stripHtml(str) {
// Remove some tags
str = str.replace(/<[^>]+>/gim, '');
// Remove BB code
str = str.replace(/\[(\w+)[^\]]*](.*?)\[\/\1]/g, '$2 ');
// Remove html and line breaks
const div = document.createElement('div');
div.innerHTML = str;
const input = document.createElement('input');
input.value = div.textContent || div.innerText || '';
return input.value;
}
(function($){
$.html2text = function(html) {
if($('#scratch_pad').length === 0) {
$('<div id="lh_scratch"></div>').appendTo('body');
}
return $('#scratch_pad').html(html).text();
};
})(jQuery);
Defina isso como um plug-in jquery e use-o da seguinte maneira:
$.html2text(htmlContent);