Réponses:
Si vous utilisez un navigateur, le moyen le plus simple consiste simplement à laisser le navigateur le faire pour vous ...
function stripHtml(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
Remarque: comme les gens l'ont remarqué dans les commentaires, il vaut mieux éviter cela si vous ne contrôlez pas la source du code HTML (par exemple, ne l'exécutez pas sur tout ce qui pourrait provenir d'une entrée utilisateur). Pour ces scénarios, vous pouvez toujours laisser le navigateur faire le travail pour vous - voir la réponse de Saba sur l'utilisation du DOMParser désormais largement disponible .
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 vous injectez via document.write
ou concaténez avec une chaîne qui contient un >
avant d'injecter via innerHTML
.
>
sera laissé dans le second. Ce n'est pas un risque d'injection cependant. Le danger se produit en raison de la <
gauche dans le premier, ce qui fait que l'analyseur HTML se trouve dans un contexte autre que l'état des données lorsque le second démarre. Notez qu'il n'y a pas de transition de l'état des données à >
.
<button onClick="dostuff('>');"></button>
Supposons que le HTML est correctement écrit, vous devez toujours tenir compte du fait qu'un signe supérieur à peut être quelque part dans le texte cité dans un attribut. Vous voudrez également supprimer tout le texte à l'intérieur des <script>
balises, au moins.
Manière la plus simple:
jQuery(html).text();
Cela récupère tout le texte d'une chaîne html.
Je voudrais partager une version éditée de la réponse approuvée du Shog9 .
Comme Mike Samuel l'a souligné avec un commentaire, cette fonction peut exécuter des codes javascript en ligne.
Mais Shog9 raison de dire "laissez le navigateur le faire pour vous ..."
alors .. voici ma version éditée, en utilisant DOMParser :
function strip(html){
var doc = new DOMParser().parseFromString(html, 'text/html');
return doc.body.textContent || "";
}
ici le code pour tester le javascript inline:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
En outre, il ne demande pas de ressources sur l'analyse (comme les images)
strip("Just text <img src='https://assets.rbl.ms/4155638/980x.jpg'>")
En tant qu'extension de la méthode jQuery, si votre chaîne peut ne pas contenir de HTML (par exemple si vous essayez de supprimer du HTML d'un champ de formulaire)
jQuery(html).text();`
retournera une chaîne vide s'il n'y a pas de HTML
Utilisation:
jQuery('<p>' + html + '</p>').text();
au lieu.
Mise à jour:
Comme cela a été souligné dans les commentaires, dans certaines circonstances, cette solution exécutera le javascript contenu dans html
si la valeur de html
pourrait être influencée par un attaquant, utilisez une solution différente.
$("<p>").html(html).text();
jQuery('<span>Text :) <img src="a" onerror="alert(1)"></span>').text()
La fonction ci-dessus publiée par hypoxyde fonctionne bien, mais je recherchais quelque chose qui convertirait essentiellement du HTML créé dans un éditeur Web RichText (par exemple FCKEditor) et effacer tout le HTML mais laisser tous les liens car je voulais à la fois le HTML et la version en texte brut pour faciliter la création des parties correctes d'un e-mail STMP (HTML et texte brut).
Après une longue période de recherche sur Google, mes collègues et moi-même avons trouvé cela en utilisant le moteur regex 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 commence comme ceci:
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>
puis après l'exécution du code, il ressemble à ceci: -
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
Comme vous pouvez le voir, tout le HTML a été supprimé et le lien a été persévéré avec le texte hyperlié est toujours intact. J'ai également remplacé les balises <p>
et <br>
par\n
(newline char) afin de conserver une sorte de formatage visuel.
Pour modifier le format du lien (par exemple BBC (Link->http://www.bbc.co.uk)
), il suffit de modifier le $2 (Link->$1)
, où $1
est l'URL / URI href et le $2
texte est un lien hypertexte. Avec les liens directement dans le corps du texte brut, la plupart des clients de messagerie SMTP les convertissent afin que l'utilisateur ait la possibilité de cliquer dessus.
Espérant que ceci puisse t'être utile.
Une amélioration de la réponse acceptée.
function strip(html)
{
var tmp = document.implementation.createHTMLDocument("New").body;
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
De cette façon, quelque chose comme ça ne fera aucun mal:
strip("<img onerror='alert(\"could run arbitrary JS here\")' src=bogus>")
Firefox, Chromium et Explorer 9+ sont sûrs. Opera Presto est toujours vulnérable. De plus, les images mentionnées dans les chaînes ne sont pas téléchargées dans Chromium et Firefox pour enregistrer les requêtes http.
<script><script>alert();
Cela devrait faire le travail sur n'importe quel environnement Javascript (NodeJS inclus).
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>
J'ai modifié la réponse de Jibberboy2000 pour inclure plusieurs <BR />
formats de balises, tout supprimer à l'intérieur <SCRIPT>
et<STYLE>
balises, formater le HTML résultant en supprimant plusieurs sauts de ligne et espaces et convertir du code codé HTML en normal. Après quelques tests, il apparaît que vous pouvez convertir la plupart des pages Web complètes en texte simple où le titre et le contenu de la page sont conservés.
Dans l'exemple 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>
devient
C'est mon titre
Cette chaîne a du code html que je veux supprimer
Dans cette ligne BBC ( http://www.bbc.co.uk ) avec lien est mentionné.
Maintenant, revenons au "texte normal" et tout en utilisant
La fonction JavaScript et la page de test ressemblent à ceci:
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;
}
Il a été utilisé avec ce 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
devrait l'être /<p.*?>/gi
.
<br>
les balises vous pouvez utiliser une bonne expression régulière à la place: /<br\s*\/?>/
cette façon , vous avez juste un remplacement au lieu de 3. En outre , il me semble que , sauf pour le décodage des entités que vous pouvez avoir un seul regex, quelque chose comme ceci: /<[a-z].*?\/?>/
.
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Il s'agit d'une version regex, plus résistante au HTML malformé, comme:
Balises non fermées
Some text <img
"<", ">" à l'intérieur des attributs de balise
Some text <img alt="x > y">
Newlines
Some <a
href="http://google.com">
Le code
var html = '<br>This <img alt="a>b" \r\n src="a_b.gif" />is > \nmy<>< > <a>"text"</a'
var text = html.replace(/<\/?("[^"]*"|'[^']*'|[^>])*(>|$)/g, "");
Une autre solution, certes moins élégante que celle de nickf ou Shog9, serait de parcourir récursivement le DOM en commençant par la balise <body> et d'ajouter chaque nœud de texte.
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 vous souhaitez conserver les liens et la structure du contenu (h1, h2, etc.), vous devez vérifier TextVersionJS.Vous pouvez l'utiliser avec n'importe quel code HTML, bien qu'il ait été créé pour convertir un e-mail HTML en texte brut.
L'utilisation est très simple. Par exemple dans 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 dans le navigateur avec pure 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>
Il fonctionne également avec require.js:
define(["textversionjs"], function(createTextVersion) {
var yourHtml = "<h1>Your HTML</h1><ul><li>goes</li><li>here.</li></ul>";
var textVersion = createTextVersion(yourHtml);
});
Après avoir essayé toutes les réponses mentionnées, la plupart sinon toutes avaient des cas marginaux et ne pouvaient pas répondre complètement à mes besoins.
J'ai commencé à explorer comment php le fait et je suis tombé sur la lib php.js qui réplique la méthode strip_tags ici: http://phpjs.org/functions/strip_tags/
allowed == ''
je pense que c'est ce que le PO a demandé, ce qui est presque ce que Byron a répondu ci-dessous (Byron a seulement eu [^>]
tort.)
allowed
paramètre, vous êtes vulnérable à XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
retours<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('');
}
Tient compte des attributs internes et des <img onerror="javascript">
éléments dom nouvellement créés.
usage:
clean_string = stripHTML("string with <html> in it")
démo:
https://jsfiddle.net/gaby_de_wilde/pqayphzd/
démo de la meilleure réponse faisant les choses terribles:
string with <a malicious="attribute \">this text should be removed, but is not">example</a>
).
Beaucoup de gens ont déjà répondu à cette question, mais j'ai pensé qu'il pourrait être utile de partager la fonction que j'ai écrite qui supprime les balises HTML d'une chaîne mais vous permet d'inclure un tableau de balises que vous ne souhaitez pas supprimer. C'est assez court et ça fonctionne bien pour moi.
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>
Je pense que le moyen le plus simple est d'utiliser simplement les expressions régulières comme quelqu'un mentionné ci-dessus. Bien qu'il n'y ait aucune raison d'en utiliser un tas. Essayer:
stringWithHTML = stringWithHTML.replace(/<\/?[a-z][a-z0-9]*[^<>]*>/ig, "");
[^<>]
avec [^>]
car une balise valide ne peut pas inclure de <
caractère, alors la vulnérabilité XSS disparaît.
J'ai apporté quelques modifications au script Jibberboy2000 original J'espère qu'il sera utile à quelqu'un
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");
Voici une version qui répond en quelque sorte au problème de sécurité 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 "";
}
}
Remarque, il retournera une chaîne vide si le balisage HTML n'est pas du XML valide (aka, les balises doivent être fermées et les attributs doivent être cités). Ce n'est pas idéal, mais cela évite d'avoir le potentiel d'exploiter la sécurité.
Si vous n'avez pas besoin d'un balisage XML valide, vous pouvez essayer d'utiliser:
var doc = document.implementation.createHTMLDocument("");
mais ce n'est pas une solution parfaite non plus pour d'autres raisons.
Vous pouvez supprimer les balises html en toute sécurité à l'aide de l' attribut sandbox iframe .
L'idée ici est qu'au lieu d'essayer de regexer notre chaîne, nous profitons de l'analyseur natif du navigateur en injectant le texte dans un élément DOM puis en interrogeant la propriété textContent
/ innerText
de cet élément.
L'élément le mieux adapté pour injecter notre texte est un iframe en bac à sable, de cette façon nous pouvons empêcher toute exécution de code arbitraire (également connu sous le nom de XSS ).
L'inconvénient de cette approche est qu'elle ne fonctionne que dans les navigateurs.
Voici ce que j'ai trouvé (non testé au combat):
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 || "";
};
})();
Utilisation ( démo ):
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
et const
. De plus, en utilisant votre solution, j'ai obtenu de nombreuses références de iframes
non utilisées dans le document. Pensez à ajouter un document.body.removeChild(sandbox)
dans le code pour les futurs lecteurs basés sur les pâtes à copier.
Le code ci-dessous vous permet de conserver certaines balises html tout en supprimant toutes les autres
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 vous utilisez le allowed
paramètre, vous êtes vulnérable à XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>')
retours<p onclick="alert(1)">mytext</p>
Il est également possible d'utiliser le fantastique analyseur HTML JS htmlparser2 pur. Voici une démo fonctionnelle:
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 sortie sera This is a simple example.
Voyez-le en action ici: https://tonicdev.com/jfahrenkrug/extract-text-from-html
Cela fonctionne à la fois sur le nœud et sur le navigateur si vous compressez votre application Web à l'aide d'un outil tel que webpack.
J'avais juste besoin de retirer les <a>
balises et de les remplacer par le texte du lien.
Cela semble très bien fonctionner.
htmlContent= htmlContent.replace(/<a.*href="(.*?)">/g, '');
htmlContent= htmlContent.replace(/<\/a>/g, '');
title="..."
.
Pour une solution plus simple, essayez ceci => https://css-tricks.com/snippets/javascript/strip-html-tags-in-javascript/
var StrippedString = OriginalString.replace(/(<([^>]+)>)/ig,"");
simple jquery 2 lignes pour dépouiller le 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 réponse acceptée fonctionne très bien la plupart du temps, cependant dans IE si la html
chaîne est, null
vous obtenez le "null"
(au lieu de ''). Fixé:
function strip(html)
{
if (html == null) return "";
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
input
l'élément ne prend en charge qu'un texte de ligne :
L'état du texte représente un contrôle d'édition de texte brut d'une ligne pour la valeur de l'élément.
function stripHtml(str) {
var tmp = document.createElement('input');
tmp.value = str;
return tmp.value;
}
Mise à jour: cela fonctionne comme prévu
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);
Définissez-le comme un plugin jquery et utilisez-le comme suit:
$.html2text(htmlContent);