Wie kann ich HTML-Tags aus einer Zeichenfolge in ASP.NET entfernen?

123

Wie kann ich mit ASP.NET die HTML-Tags einer bestimmten Zeichenfolge zuverlässig entfernen (dh keinen regulären Ausdruck verwenden)? Ich suche so etwas wie PHPs strip_tags.

Beispiel:

<ul><li>Hello</li></ul>

Ausgabe:

"Hallo"

Ich versuche, das Rad nicht neu zu erfinden, aber ich habe bisher nichts gefunden, was meinen Bedürfnissen entspricht.

Daniel
quelle
Ich würde mir vorstellen, dass PHP strip_tags hinter den Kulissen Regex verwendet!
Stevewell Well
10
@ Daniel: weil Regex dabei sehr schlecht ist, besonders wenn du verschachtelt hast.
Joel Coehoorn
Hmm, sieht nicht so aus, als ob die Strip_Tags von PHP besonders zuverlässig sind, auch nicht in den offiziellen Notizen und den Kommentaren: uk.php.net/strip_tags
Zhaph - Ben Duguid

Antworten:

112

Wenn nur alle HTML-Tags aus einer Zeichenfolge entfernt werden, funktioniert dies auch mit Regex zuverlässig . Ersetzen:

<[^>]*(>|$)

mit der leeren Zeichenfolge global. Vergessen Sie nicht, die Zeichenfolge anschließend zu normalisieren und zu ersetzen:

[\s\r\n]+

mit einem einzigen Leerzeichen und Trimmen des Ergebnisses. Ersetzen Sie optional alle HTML-Zeichenentitäten durch die tatsächlichen Zeichen.

Hinweis :

  1. Es gibt eine Einschränkung: HTML und XML erlauben >Attributwerte. Diese Lösung gibt bei Auftreten solcher Werte ein fehlerhaftes Markup zurück.
  2. Die Lösung ist technisch sicher wie in: Das Ergebnis enthält niemals etwas, das für Cross-Site-Scripting oder zum Aufbrechen eines Seitenlayouts verwendet werden könnte. Es ist einfach nicht sehr sauber.
  3. Wie bei allen Dingen wie HTML und Regex:
    Verwenden Sie einen geeigneten Parser, wenn Sie ihn unter allen Umständen richtig machen müssen.
Tomalak
quelle
52
Obwohl nicht angefordert, denke ich, dass viele Leser auch die HTM-Codierung entfernen möchten, wie z &quote;. Ich kombiniere es WebUtility.HtmlDecodedamit (was wiederum keine Tags entfernt). Verwenden Sie es nach dem Entfernen des Tags, da es möglicherweise neu geschrieben wird &gt;und &lt;. ZBWebUtility.HtmlDecode(Regex.Replace(myTextVariable, "<[^>]*(>|$)", string.Empty))
Yahoo Serious
@YahooSerious Vielen Dank für ein Beispiel. Das funktioniert super. Danke dir.
SearchForKnowledge
Html Agility Pack ist der richtige Weg. Ich habe es vor langer Zeit in Webformularen verwendet, um ganze Webseiten zu entfernen und Inhalte zu verwenden!
Bojangles
3
@YahooSerious dies erlaubt einen XSS-Vektor in jedoch & gt; Skript & lt; Alarm ("XXS"); & gt; / script & lt; Wird nicht von der Regex bereinigt, sondern von HtmlDecode in <script> alert ("XXS") konvertiert; </ script>
1
@Heather Sehr guter Punkt. Das Entfernen von HTML-Tags müsste nach dem Entschlüsseln der Entität erneut durchgeführt werden.
Tomalak
76

Laden Sie jetzt HTMLAgilityPack herunter! ;) LInk herunterladen

Auf diese Weise können Sie HTML laden und analysieren. Anschließend können Sie im DOM navigieren und die inneren Werte aller Attribute extrahieren. Im Ernst, Sie benötigen maximal 10 Codezeilen. Es ist eine der größten kostenlosen .net-Bibliotheken da draußen.

Hier ist ein Beispiel:

            string htmlContents = new System.IO.StreamReader(resultsStream,Encoding.UTF8,true).ReadToEnd();

            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(htmlContents);
            if (doc == null) return null;

            string output = "";
            foreach (var node in doc.DocumentNode.ChildNodes)
            {
                output += node.InnerText;
            }
Serapth
quelle
2
Sie können sogar jeden text()Knoten abfragen , den Inhalt und die Zeichenfolge zuschneiden. Fügen Sie diese mit Leerzeichen hinzu. IEnumerable<string> allText = doc.DocumentNode.SelectNodes("//text()").Select(n => n.InnerText.Trim())
Jessehouwing
oder verwenden Sie einfach doc.DocumentNode.InnerText, obwohl dies einige Probleme mit der
Behandlung von
17
Warum der if (doc == null)Scheck? Das ist immer falsch, nicht wahr?
Avesse
66
Regex.Replace(htmlText, "<.*?>", string.Empty);
user95144
quelle
Einfach und nett. Vielen Dank!
Tillito
5
Hat viele Probleme - behandelt keine Attribute mit <oder> und eignet sich nicht für Tags, die mehr als eine Zeile umfassen, es sei denn, sie werden mit ausgeführt RegexOptions.SingleLine.
ChrisF
2
Nein, benutze "<[^>] *>".
Paul Kienitz
11
protected string StripHtml(string Txt)
{
    return Regex.Replace(Txt, "<(.|\\n)*?>", string.Empty);
}    

Protected Function StripHtml(Txt as String) as String
    Return Regex.Replace(Txt, "<(.|\n)*?>", String.Empty)
End Function
meramez
quelle
2
Funktioniert nicht in vielen Fällen, einschließlich Nicht-Unix-Zeilenumbrüchen.
ChrisF
6

Ich habe dies in den asp.net-Foren gepostet und es scheint immer noch eine der einfachsten Lösungen zu sein. Ich kann nicht garantieren, dass es das schnellste oder effizienteste ist, aber es ist ziemlich zuverlässig. In .NET können Sie die HTML Web Control-Objekte selbst verwenden. Alles, was Sie wirklich tun müssen, ist, Ihre Zeichenfolge in ein temporäres HTML-Objekt wie ein DIV einzufügen und dann den integrierten 'InnerText' zu verwenden, um den gesamten Text abzurufen, der nicht in Tags enthalten ist. Unten finden Sie ein einfaches C # -Beispiel:


System.Web.UI.HtmlControls.HtmlGenericControl htmlDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("div");
htmlDiv.InnerHtml = htmlString;
String plainText = htmlDiv.InnerText;
Michael Tipton
quelle
das scheint nicht zu funktionieren, ich habe es mit einfachem InnerHtml = "<b> foo </ b>" getestet; und InnerText hat den Wert "<b> foo </ b>" :(
Axarydax
Tu das nicht. Diese Lösung injiziert nicht codiertes HTML direkt in die Ausgabe. Dies würde Sie für Cross Site Scripting-Angriffe weit offen lassen - Sie haben gerade jedem, der die HTML-Zeichenfolge ändern kann, erlaubt, beliebiges HTML und Javascript in Ihre Anwendung einzufügen!
Saille
5

Ich habe eine ziemlich schnelle Methode in c # geschrieben, die die Hölle aus dem Regex schlägt. Es wird in einem Artikel über CodeProject gehostet.

Seine Vorteile sind neben einer besseren Leistung die Möglichkeit, benannte und nummerierte HTML-Entitäten (wie &amp;amp;und &203;) und das Ersetzen von Kommentarblöcken und mehr zu ersetzen .

Bitte lesen Sie den entsprechenden Artikel über CodeProject .

Danke dir.

Andrei Rînea
quelle
4

Für diejenigen unter Ihnen, die das HtmlAgilityPack nicht verwenden können, ist der XML-Reader von .NET eine Option. Dies kann jedoch bei gut formatiertem HTML fehlschlagen. Fügen Sie daher immer einen Haken mit regx als Backup hinzu. Beachten Sie, dass dies NICHT schnell ist, aber eine gute Gelegenheit für den Schritt der alten Schule durch das Debuggen bietet.

public static string RemoveHTMLTags(string content)
    {
        var cleaned = string.Empty;
        try
        {
            StringBuilder textOnly = new StringBuilder();
            using (var reader = XmlNodeReader.Create(new System.IO.StringReader("<xml>" + content + "</xml>")))
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Text)
                        textOnly.Append(reader.ReadContentAsString());
                }
            }
            cleaned = textOnly.ToString();
        }
        catch
        {
            //A tag is probably not closed. fallback to regex string clean.
            string textOnly = string.Empty;
            Regex tagRemove = new Regex(@"<[^>]*(>|$)");
            Regex compressSpaces = new Regex(@"[\s\r\n]+");
            textOnly = tagRemove.Replace(content, string.Empty);
            textOnly = compressSpaces.Replace(textOnly, " ");
            cleaned = textOnly;
        }

        return cleaned;
    }
Eimer
quelle
3
string result = Regex.Replace(anytext, @"<(.|\n)*?>", string.Empty);
Alex
quelle
1

Für diejenigen, die sich darüber beschweren, dass die Lösung von Michael Tiptop nicht funktioniert, gibt es hier die .Net4 + -Methode:

public static string StripTags(this string markup)
{
    try
    {
        StringReader sr = new StringReader(markup);
        XPathDocument doc;
        using (XmlReader xr = XmlReader.Create(sr,
                           new XmlReaderSettings()
                           {
                               ConformanceLevel = ConformanceLevel.Fragment
                               // for multiple roots
                           }))
        {
            doc = new XPathDocument(xr);
        }

        return doc.CreateNavigator().Value; // .Value is similar to .InnerText of  
                                           //  XmlDocument or JavaScript's innerText
    }
    catch
    {
        return string.Empty;
    }
}
Annie
quelle
1
using System.Text.RegularExpressions;

string str = Regex.Replace(HttpUtility.HtmlDecode(HTMLString), "<.*?>", string.Empty);
Karan
quelle
0

Ich habe mir die hier vorgeschlagenen Regex-basierten Lösungen angesehen und sie erfüllen mich nur in den trivialsten Fällen mit Vertrauen. Eine spitze Klammer in einem Attribut ist alles, was Sie brauchen, um zu brechen, geschweige denn falsch formuliertes HTML aus der Wildnis. Und was ist mit Entitäten wie &amp;? Wenn Sie HTML in einfachen Text konvertieren möchten, müssen Sie auch Entitäten dekodieren.

Also schlage ich die folgende Methode vor.

Mit HtmlAgilityPack entfernt diese Erweiterungsmethode effizient alle HTML-Tags aus einem HTML-Fragment. Dekodiert auch HTML-Entitäten wie &amp;. Gibt nur die inneren Textelemente mit einer neuen Zeile zwischen den einzelnen Textelementen zurück.

public static string RemoveHtmlTags(this string html)
{
        if (String.IsNullOrEmpty(html))
            return html;

        var doc = new HtmlAgilityPack.HtmlDocument();
        doc.LoadHtml(html);

        if (doc.DocumentNode == null || doc.DocumentNode.ChildNodes == null)
        {
            return WebUtility.HtmlDecode(html);
        }

        var sb = new StringBuilder();

        var i = 0;

        foreach (var node in doc.DocumentNode.ChildNodes)
        {
            var text = node.InnerText.SafeTrim();

            if (!String.IsNullOrEmpty(text))
            {
                sb.Append(text);

                if (i < doc.DocumentNode.ChildNodes.Count - 1)
                {
                    sb.Append(Environment.NewLine);
                }
            }

            i++;
        }

        var result = sb.ToString();

        return WebUtility.HtmlDecode(result);
}

public static string SafeTrim(this string str)
{
    if (str == null)
        return null;

    return str.Trim();
}

Wenn Sie wirklich ernst sind, würden Sie den Inhalt bestimmter HTML - Tags ignorieren zu ( <script>, <style>, <svg>, <head>, <object>in den Sinn kommen!) , Weil sie wahrscheinlich lesbaren Inhalt nicht in dem Sinne enthalten sind wir nach. Was Sie dort tun, hängt von Ihren Umständen ab und davon, wie weit Sie gehen möchten. Mit HtmlAgilityPack ist es jedoch ziemlich trivial, ausgewählte Tags auf die Whitelist oder Blacklist zu setzen.

Wenn Sie den Inhalt wieder auf eine HTML-Seite rendern, stellen Sie sicher, dass Sie die XSS-Sicherheitsanfälligkeit verstehen und wissen, wie Sie sie verhindern können. Codieren Sie daher immer den vom Benutzer eingegebenen Text, der wieder auf eine HTML-Seite gerendert wird ( >wird &gt;usw.).

Saille
quelle
0

Für den zweiten Parameter, dh einige Tags behalten, benötigen Sie möglicherweise Code wie diesen, indem Sie HTMLagilityPack verwenden:

public string StripTags(HtmlNode documentNode, IList keepTags)
{
    var result = new StringBuilder();
        foreach (var childNode in documentNode.ChildNodes)
        {
            if (childNode.Name.ToLower() == "#text")
            {
                result.Append(childNode.InnerText);
            }
            else
            {
                if (!keepTags.Contains(childNode.Name.ToLower()))
                {
                    result.Append(StripTags(childNode, keepTags));
                }
                else
                {
                    result.Append(childNode.OuterHtml.Replace(childNode.InnerHtml, StripTags(childNode, keepTags)));
                }
            }
        }
        return result.ToString();
    }

Weitere Erläuterungen auf dieser Seite: http://nalgorithm.com/2015/11/20/strip-html-tags-of-an-html-in-c-strip_html-php-equivalent/

Yuksel Daskin
quelle
0

Sie können dies auch mit AngleSharp tun, das eine Alternative zu HtmlAgilityPack darstellt (nicht, dass HAP schlecht ist). Es ist einfacher als HAP, den Text aus einer HTML-Quelle zu holen.

var parser = new HtmlParser();
var htmlDocument = parser.ParseDocument(source);
var text = htmlDocument.Body.Text();

Sie können sich den Abschnitt mit den wichtigsten Funktionen ansehen, in dem sie als "besser" als HAP eingestuft werden. Ich denke größtenteils, es ist wahrscheinlich übertrieben für die aktuelle Frage, aber dennoch ist es eine interessante Alternative.

Yepeekai
quelle
-4

Einfach benutzen string.StripHTML();

user3638478
quelle
3
Wie @Serpiton betont, gibt es in der BCL keine solche Methode. Könnten Sie auf eine Implementierung dieser Methode verweisen oder eine eigene bereitstellen?
Sven Grosen