Respuestas:
Si está ejecutando en un navegador, entonces la forma más fácil es dejar que el navegador lo haga por usted ...
function stripHtml(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Nota: como la gente ha señalado en los comentarios, es mejor evitar esto si no controlas la fuente del HTML (por ejemplo, no ejecutes esto en nada que pueda provenir de la entrada del usuario). Para esos escenarios, aún puede dejar que el navegador haga el trabajo por usted: vea la respuesta de Saba sobre el uso del ahora disponible 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)"
si está inyectando document.write
o concatenando con una cadena que contiene un >
antes de inyectar vía innerHTML
.
>
quedará en el segundo. Sin embargo, eso no es un riesgo de inyección. El peligro se produce debido a la <
izquierda en el primero, lo que hace que el analizador HTML esté en un contexto distinto del estado de los datos cuando se inicia el segundo. Tenga en cuenta que no hay transición del estado de datos en adelante >
.
<button onClick="dostuff('>');"></button>
Asumir HTML correctamente escrito, aún debe tener en cuenta que un signo mayor podría estar en algún lugar del texto citado en un atributo. También querrás eliminar todo el texto dentro de las <script>
etiquetas, al menos.
La forma más simple:
jQuery(html).text();
Eso recupera todo el texto de una cadena de HTML.
Me gustaría compartir una versión editada de la respuesta aprobada del Shog9 .
Como Mike Samuel señaló con un comentario, esa función puede ejecutar códigos JavaScript en línea.
Pero Shog9 tiene razón cuando dice "deja que el navegador lo haga por ti ..."
entonces ... aquí mi versión editada, usando DOMParser :
function strip(html){
var doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || "";
}
aquí el código para probar el javascript en línea:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Además, no solicita recursos en análisis (como imágenes)
strip("Just text <img src='https://assets.rbl.ms/4155638/980x.jpg'>")
Como una extensión del método jQuery, si su cadena podría no contener HTML (por ejemplo, si está tratando de eliminar HTML de un campo de formulario)
jQuery(html).text();`
devolverá una cadena vacía si no hay HTML
Utilizar:
jQuery('<p>' + html + '</p>').text();
en lugar.
Actualización:
Como se ha señalado en los comentarios, en algunas circunstancias esta solución ejecutará javascript contenido dentro html
si el html
atacante puede influir en el valor de , use una solución diferente.
$("<p>").html(html).text();
jQuery('<span>Text :) <img src="a" onerror="alert(1)"></span>').text()
La función anterior publicada por hypoxide funciona bien, pero buscaba algo que básicamente convirtiera HTML creado en un editor de texto enriquecido web (por ejemplo, FCKEditor) y borrara todo HTML, pero dejara todos los enlaces porque quería tanto el HTML como la versión de texto sin formato para ayudar a crear las partes correctas para un correo electrónico STMP (HTML y texto sin formato).
Después de un largo tiempo de búsqueda en Google, a mí y a mis colegas se les ocurrió usar el motor de expresiones regulares en 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, "");
La str
variable comienza así:
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>
y luego de que el código se haya ejecutado se ve así
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 puede ver, todo el HTML se ha eliminado y el enlace se ha perseverado con el texto hipervinculado todavía está intacto. También he reemplazado las etiquetas <p>
y <br>
con \n
(newline char) para que se haya retenido algún tipo de formato visual.
Para cambiar el formato del enlace (p. Ej. BBC (Link->http://www.bbc.co.uk)
) Simplemente edite $2 (Link->$1)
, donde $1
está la URL / URI href y el $2
texto hipervinculado. Con los enlaces directamente en el cuerpo del texto plano, la mayoría de los clientes de correo SMTP los convierten para que el usuario pueda hacer clic en ellos.
Espero que encuentres esto útil.
Una mejora a la respuesta aceptada.
function strip(html)
{
var tmp = document.implementation.createHTMLDocument("New").body;
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
De esta manera, algo así no hará daño:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Firefox, Chromium y Explorer 9+ son seguros. Opera Presto sigue siendo vulnerable. Además, las imágenes mencionadas en las cadenas no se descargan en Chromium y Firefox guardando solicitudes http.
<script><script>alert();
Esto debería hacer el trabajo en cualquier entorno Javascript (NodeJS incluido).
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>
Alteré la respuesta de Jibberboy2000 para incluir varios <BR />
formatos de etiquetas, retire todo el interior <SCRIPT>
y <STYLE>
las etiquetas, formatear el HTML resultante mediante la eliminación de múltiples saltos de línea y espacios y convertir algo de código HTML codificada en normal. Después de algunas pruebas, parece que puede convertir la mayoría de las páginas web completas en texto simple donde se retienen el título y el contenido de la página.
En el ejemplo simple,
<!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>
se convierte
Este es mi titulo
Esta cadena tiene código html que quiero eliminar
En esta línea se menciona BBC ( http://www.bbc.co.uk ) con enlace.
Ahora de vuelta al "texto normal" y cosas usando
La función de JavaScript y la página de prueba se ven así:
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;
}
Fue utilizado con 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
debería ser /<p.*?>/gi
.
<br>
etiquetas que podría usar una buena expresión regular en su lugar: /<br\s*\/?>/
de esa manera usted tiene sólo una sustitución en lugar de 3. También me parece que a excepción de la decodificación de las entidades puede tener una sola expresión regular, algo como esto: /<[a-z].*?\/?>/
.
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Esta es una versión regex, que es más resistente a HTML con formato incorrecto, como:
Etiquetas no cerradas
Some text <img
"<", ">" dentro de los atributos de la etiqueta
Some text <img alt="x > y">
Newlines
Some <a
href="http://google.com">
El 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, "");
Otra solución, sin duda menos elegante que la de nickf o Shog9, sería recorrer recursivamente el DOM comenzando en la etiqueta <body> y agregar cada nodo 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;
}
Si desea mantener los enlaces y la estructura del contenido (h1, h2, etc.), debe consultar TextVersionJS . Puede usarlo con cualquier HTML, aunque se creó para convertir un correo electrónico HTML a texto sin formato.
El uso es muy simple. Por ejemplo en node.js:
var createTextVersion = require("textversionjs");
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
var textVersion = createTextVersion(yourHtml);
O en el navegador con 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>
También funciona con require.js:
define(["textversionjs"], function(createTextVersion) {
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
var textVersion = createTextVersion(yourHtml);
});
Después de probar todas las respuestas mencionadas, la mayoría, si no todas, tenían casos extremos y no podían satisfacer completamente mis necesidades.
Comencé a explorar cómo lo hace php y encontré la lib php.js que replica el método strip_tags aquí: http://phpjs.org/functions/strip_tags/
allowed == ''
creo que es lo que solicitó el OP, que es casi lo que Byron respondió a continuación (Byron solo se [^>]
equivocó)
allowed
parámetro, es vulnerable a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
regresa<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('');
}
Cuentas para> atributos internos y <img onerror="javascript">
en elementos dom recién creados.
uso:
clean_string = stripHTML("string with <html> in it")
manifestación:
https://jsfiddle.net/gaby_de_wilde/pqayphzd/
demostración de la respuesta superior haciendo las cosas terribles:
string with <a malicious="attribute \">this text should be removed, but is not">example</a>
).
Mucha gente ya ha respondido esto, pero pensé que podría ser útil compartir la función que escribí que quita las etiquetas HTML de una cadena pero le permite incluir una serie de etiquetas que no desea quitar. Es bastante corto y ha estado funcionando bien para mí.
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>
Creo que la forma más fácil es usar expresiones regulares como alguien mencionado anteriormente. Aunque no hay razón para usar un montón de ellos. Tratar:
stringWithHTML = stringWithHTML.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, "");
[^<>]
con [^>]
porque una etiqueta válida no puede incluir un <
carácter, entonces la vulnerabilidad XSS desaparece.
Hice algunas modificaciones al script original de Jibberboy2000 Espero que sea útil para alguien
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");
Aquí hay una versión que aborda el problema de seguridad 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 "";
}
}
Tenga en cuenta que devolverá una cadena vacía si el marcado HTML no es XML válido (es decir, las etiquetas deben estar cerradas y los atributos deben estar entre comillas). Esto no es ideal, pero evita el problema de tener el potencial de explotación de seguridad.
Si no es necesario tener un marcado XML válido, puede intentar usar:
var doc = document.implementation.createHTMLDocument("");
pero esa no es una solución perfecta tampoco por otras razones.
Puede quitar etiquetas html de forma segura utilizando el atributo iframe sandbox .
La idea aquí es que, en lugar de intentar regexificar nuestra cadena, aprovechamos el analizador nativo del navegador al inyectar el texto en un elemento DOM y luego consultar la propiedad textContent
/ innerText
de ese elemento.
El elemento más adecuado para inyectar nuestro texto es un iframe de espacio aislado, de esa manera podemos evitar cualquier ejecución de código arbitrario (también conocido como XSS ).
La desventaja de este enfoque es que solo funciona en los navegadores.
Esto es lo que se me ocurrió (no probado en batalla):
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
y const
. Además, al usar su solución, obtuve muchas referencias de iframes
no utilizadas dentro del documento. Considere agregar un document.body.removeChild(sandbox)
código en el futuro para futuros lectores basados en copy-pasta.
El siguiente código le permite retener algunas etiquetas html mientras elimina todas las demás
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
). Si usa el allowed
parámetro, es vulnerable a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
regresa<p onclick="alert(1)">mytext</p>
También es posible usar el fantástico analizador htmlparser2 pure JS HTML. Aquí hay una demostración funcional:
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('');
La salida será This is a simple example.
Véalo en acción aquí: https://tonicdev.com/jfahrenkrug/extract-text-from-html
Esto funciona tanto en el nodo como en el navegador si empaqueta su aplicación web utilizando una herramienta como webpack.
Solo necesitaba quitar las <a>
etiquetas y reemplazarlas con el texto del enlace.
Esto parece funcionar muy bien.
htmlContent= htmlContent.replace(/<a.*href="(.*?)">/g, '');
htmlContent= htmlContent.replace(/<\/a>/g, '');
title="..."
.
Para una solución más fácil, intente esto => https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
var StrippedString = OriginalString.replace(/(<([^>]+)>)/ig,"");
jquery simple de 2 líneas para quitar el 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
La respuesta aceptada funciona bien en su mayoría, sin embargo, en IE, si la html
cadena se null
obtiene "null"
(en lugar de ''). Fijo:
function strip(html)
{
if (html == null) return "";
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Usando Jquery:
function stripTags() {
return $('<p></p>').html(textToEscape).text()
}
input
el elemento admite solo una línea de texto :
El estado del texto representa un control de edición de texto sin formato de una línea para el valor del elemento.
function stripHtml(str) {
var tmp = document.createElement('input');
tmp.value = str;
return tmp.value;
}
Actualización: esto funciona como se esperaba
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 esto como un complemento jquery y úselo de la siguiente manera:
$.html2text(htmlContent);