Risposte:
Se stai utilizzando un browser, il modo più semplice è lasciare che il browser lo faccia per te ...
function stripHtml(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Nota: come hanno notato le persone nei commenti, è meglio evitarlo se non si controlla l'origine dell'HTML (ad esempio, non eseguirlo su qualcosa che potrebbe provenire dall'input dell'utente). Per quegli scenari, puoi comunque lasciare che il browser faccia il lavoro per te - vedi la risposta di Saba sull'uso del DOMParser ora ampiamente disponibile .
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 stai iniettando via document.write
o concatenando una stringa che contiene un >
prima di iniettare via innerHTML
.
>
sarà lasciato nel secondo. Questo non è un rischio di iniezione però. Il pericolo si verifica a causa della <
sinistra nel primo, che fa sì che il parser HTML si trovi in un contesto diverso dallo stato dei dati all'avvio del secondo. Nota che non c'è transizione dallo stato dei dati in poi >
.
<button onClick="dostuff('>');"></button>
Assumendo un HTML scritto correttamente, devi ancora tener conto del fatto che un segno maggiore di potrebbe essere da qualche parte nel testo citato in un attributo. Inoltre, dovresti rimuovere tutto il testo all'interno dei <script>
tag, almeno.
Il modo più semplice:
jQuery(html).text();
Ciò recupera tutto il testo da una stringa di HTML.
Vorrei condividere una versione modificata della risposta approvata da Shog9 .
Come ha sottolineato Mike Samuel con un commento, quella funzione può eseguire codici javascript in linea.
Ma Shog9 ragione quando dice "lascia che il browser lo faccia per te ..."
quindi .. qui la mia versione modificata, usando DOMParser :
function strip(html){
var doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || "";
}
qui il codice per testare il javascript inline:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Inoltre, non richiede risorse all'analisi (come le immagini)
strip("Just text <img src='https://assets.rbl.ms/4155638/980x.jpg'>")
Come estensione del metodo jQuery, se la tua stringa potrebbe non contenere HTML (ad esempio se stai provando a rimuovere HTML da un campo modulo)
jQuery(html).text();`
restituirà una stringa vuota se non c'è HTML
Uso:
jQuery('<p>' + html + '</p>').text();
anziché.
Aggiornamento:
Come è stato sottolineato nei commenti, in alcune circostanze questa soluzione eseguirà javascript contenuto all'interno html
se il valore di html
potrebbe essere influenzato da un utente malintenzionato, utilizzare una soluzione diversa.
$("<p>").html(html).text();
jQuery('<span>Text :) <img src="a" onerror="alert(1)"></span>').text()
La funzione di cui sopra pubblicata da hypoxide funziona bene, ma stavo cercando qualcosa che convertisse sostanzialmente l'HTML creato in un editor Web RichText (ad esempio FCKEditor) e cancellasse tutto l'HTML, lasciando tutti i collegamenti a causa del fatto che volevo sia l'HTML che il la versione in testo normale per facilitare la creazione delle parti corrette in un'e-mail STMP (sia HTML che testo semplice).
Dopo un lungo periodo di ricerche su Google, me stesso e i miei colleghi hanno scoperto questo usando il motore regex in 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
variabile inizia così:
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 dopo che il codice è stato eseguito appare così: -
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
Come puoi vedere, tutto l'HTML è stato rimosso e il collegamento è stato perseverato con il testo con collegamento ipertestuale ancora intatto. Inoltre ho sostituito i tag <p>
e <br>
con\n
(newline char) in modo che sia stata mantenuta una sorta di formattazione visiva.
Per cambiare il formato del collegamento (es. BBC (Link->http://www.bbc.co.uk)
) Basta modificare $2 (Link->$1)
, dove si $1
trova l'URL / URI href e il $2
testo è il collegamento ipertestuale. Con i collegamenti direttamente nel corpo del testo normale, la maggior parte dei client di posta SMTP li converte in modo che l'utente abbia la possibilità di fare clic su di essi.
Spero che lo trovi utile.
Un miglioramento alla risposta accettata.
function strip(html)
{
var tmp = document.implementation.createHTMLDocument("New").body;
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
In questo modo qualcosa in esecuzione in questo modo non farà alcun danno:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Firefox, Chromium ed Explorer 9+ sono sicuri. Opera Presto è ancora vulnerabile. Anche le immagini menzionate nelle stringhe non vengono scaricate in Chromium e Firefox salvando le richieste http.
<script><script>alert();
Questo dovrebbe funzionare in qualsiasi ambiente Javascript (incluso NodeJS).
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>
Ho modificato la risposta di Jibberboy2000 per includere diversi <BR />
formati di tag, rimuovere tutto all'interno <SCRIPT>
e<STYLE>
tag, formattare l'HTML risultante rimuovendo più interruzioni di riga e spazi e convertendo un codice con codice HTML in normale. Dopo alcuni test sembra che sia possibile convertire la maggior parte delle pagine Web complete in testo semplice in cui vengono conservati il titolo e il contenuto della pagina.
Nel semplice esempio,
<!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>
diventa
Questo è il mio titolo
Questa stringa ha un codice HTML che voglio rimuovere
In questa linea viene menzionata la BBC ( http://www.bbc.co.uk ) con link.
Ora torniamo al "testo normale" e roba usando
La funzione JavaScript e la pagina di test sono:
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;
}
È stato usato con questo 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
dovrebbe essere /<p.*?>/gi
.
<br>
i tag si potrebbe usare una buona espressione regolare invece: /<br\s*\/?>/
in questo modo si dispone di un solo sostituire invece di 3. Inoltre mi sembra che, a parte la decodifica delle entità si può avere un unico regex, qualcosa di simile a questo: /<[a-z].*?\/?>/
.
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Questa è una versione regex, che è più resistente all'HTML malformato, come:
Tag non chiusi
Some text <img
"<", ">" all'interno degli attributi del tag
Some text <img alt="x > y">
newlines
Some <a
href="http://google.com">
Il codice
var html = '<br>This <img alt="a>b" \r\n src="a_b.gif" />is > \nmy<>< > <a>"text"</a'
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Un'altra soluzione, sicuramente meno elegante di quella di nickf o Shog9, sarebbe quella di ricorrere in modo ricorsivo al DOM partendo dal tag <body> e aggiungendo ciascun nodo di testo.
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 vuoi mantenere i collegamenti e la struttura del contenuto (h1, h2, ecc.) Allora dovresti dare un'occhiata a TextVersionJS Puoi usarlo con qualsiasi HTML, anche se è stato creato per convertire una e-mail HTML in testo semplice.
L'utilizzo è molto semplice. Ad esempio in 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 nel browser 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>
Funziona anche 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);
});
Dopo aver provato tutte le risposte menzionate di più, se non tutte hanno avuto casi limite e non sono state in grado di supportare completamente le mie esigenze.
Ho iniziato a esplorare come funziona php e ho trovato la lib php.js che replica il metodo strip_tags qui: http://phpjs.org/functions/strip_tags/
allowed == ''
penso che sia ciò che l'OP ha richiesto, il che è quasi ciò che Byron ha risposto di seguito (Byron ha solo [^>]
sbagliato.)
allowed
parametro sei vulnerabile a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
restituisce<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('');
}
Conta per> attributi interni e <img onerror="javascript">
in elementi dom appena creati.
utilizzo:
clean_string = stripHTML("string with <html> in it")
demo:
https://jsfiddle.net/gaby_de_wilde/pqayphzd/
demo della risposta migliore facendo le cose terribili:
string with <a malicious="attribute \">this text should be removed, but is not">example</a>
.).
Molte persone hanno già risposto a questa domanda, ma ho pensato che potesse essere utile condividere la funzione che ho scritto che spoglia tag HTML da una stringa ma ti consente di includere un array di tag che non vuoi eliminare. È piuttosto corto e ha funzionato bene per me.
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>
Penso che il modo più semplice sia usare le espressioni regolari come qualcuno sopra menzionato. Anche se non c'è motivo di usarne un sacco. Provare:
stringWithHTML = stringWithHTML.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, "");
[^<>]
con [^>]
perché un tag valido non può includere un <
carattere, quindi la vulnerabilità XSS scompare.
Ho apportato alcune modifiche allo script originale di Jibberboy2000 Spero che possa essere utile per qualcuno
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");
Ecco una versione che risolve i problemi di sicurezza di @ 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 "";
}
}
Nota, restituirà una stringa vuota se il markup HTML non è XML valido (ovvero, i tag devono essere chiusi e gli attributi devono essere quotati). Questo non è l'ideale, ma evita il problema di avere il potenziale di sfruttamento della sicurezza.
Se non hai un markup XML valido è un requisito per te, puoi provare a usare:
var doc = document.implementation.createHTMLDocument("");
ma questa non è una soluzione perfetta neanche per altri motivi.
Puoi rimuovere in sicurezza i tag html usando l' attributo sandbox iframe .
L'idea qui è che invece di provare a regexare la nostra stringa, sfruttiamo il parser nativo del browser iniettando il testo in un elemento DOM e quindi interrogando la proprietà textContent
/ innerText
di tale elemento.
L'elemento più adatto in cui iniettare il nostro testo è un iframe sandbox, in questo modo possiamo impedire qualsiasi esecuzione di codice arbitrario (noto anche come XSS ).
L'aspetto negativo di questo approccio è che funziona solo nei browser.
Ecco cosa mi è venuto in mente (non testato in battaglia):
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 || "";
};
})();
Utilizzo ( 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
. Inoltre, usando la tua soluzione, ho ricevuto molti riferimenti di iframes
non utilizzati all'interno del documento. Prendi in considerazione l'aggiunta di un document.body.removeChild(sandbox)
codice nel codice per i futuri lettori basati su copia-pasta.
Il codice seguente ti consente di conservare alcuni tag html mentre rimuovi tutti gli altri
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 usi il allowed
parametro sei vulnerabile a XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
restituisce<p onclick="alert(1)">mytext</p>
È anche possibile utilizzare il fantastico htmlparser2 parser HTML puro JS HTML . Ecco una demo funzionante:
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('');
L'output sarà This is a simple example.
Guardalo in azione qui: https://tonicdev.com/jfahrenkrug/extract-text-from-html
Funziona sia nel nodo che nel browser se impacchetti la tua applicazione web usando uno strumento come il webpack.
Avevo solo bisogno di eliminare il <a>
tag e sostituirli con il testo del collegamento.
Questo sembra funzionare alla grande.
htmlContent= htmlContent.replace(/<a.*href="(.*?)">/g, '');
htmlContent= htmlContent.replace(/<\/a>/g, '');
title="..."
.
Per una soluzione più semplice, prova questo => https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
var StrippedString = OriginalString.replace(/(<([^>]+)>)/ig,"");
semplice jquery a 2 righe per rimuovere l'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 risposta accettata funziona bene soprattutto, tuttavia in IE se la html
stringa è null
ottieni "null"
(invece di ''). Fisso:
function strip(html)
{
if (html == null) return "";
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
input
l'elemento supporta solo una riga di testo :
Lo stato del testo rappresenta un controllo di modifica del testo in una riga per il valore dell'elemento.
function stripHtml(str) {
var tmp = document.createElement('input');
tmp.value = str;
return tmp.value;
}
Aggiornamento: funziona come previsto
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);
Definisci questo come un plugin jquery e usalo come segue:
$.html2text(htmlContent);