Bagaimana cara menghapus tag HTML dari string di ASP.NET?


123

Menggunakan ASP.NET, bagaimana cara menghapus tag HTML dari string yang diberikan dengan andal (yaitu tidak menggunakan regex)? Saya mencari sesuatu seperti PHP strip_tags.

Contoh:

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

Keluaran:

"Halo"

Saya mencoba untuk tidak menemukan kembali roda, tetapi sejauh ini saya belum menemukan apa pun yang memenuhi kebutuhan saya.


Saya membayangkan bahwa PHP strip_tags menggunakan regex di belakang layar!
stevehipwell

10
@Daniel: karena regex sangat buruk dalam hal itu, terutama jika Anda memiliki sarang.
Joel Coehoorn

Hmm, sepertinya Strip_Tags PHP tidak dapat diandalkan baik pada catatan resmi maupun komentar: uk.php.net/strip_tags
- Ben Duguid

Jawaban:


112

Jika hanya menghapus semua tag HTML dari sebuah string, ini juga dapat diandalkan dengan regex. Menggantikan:

<[^>]*(>|$)

dengan string kosong, secara global. Jangan lupa untuk menormalkan string setelahnya, ganti:

[\s\r\n]+

dengan satu spasi, dan pemangkasan hasilnya. Secara opsional, ganti entitas karakter HTML apa pun kembali ke karakter sebenarnya.

Catatan :

  1. Ada batasan: HTML dan XML memungkinkan >nilai atribut. Solusi ini akan mengembalikan markup rusak saat menemukan nilai-nilai tersebut.
  2. Solusinya secara teknis aman, seperti dalam: Hasilnya tidak akan pernah berisi apa pun yang dapat digunakan untuk melakukan skrip lintas situs atau merusak tata letak halaman. Hanya saja tidak terlalu bersih.
  3. Seperti semua hal tentang HTML dan regex:
    Gunakan parser yang tepat jika Anda harus melakukannya dengan benar dalam segala situasi.

52
Meskipun tidak diminta, saya rasa banyak pembaca akan ingin juga menghapus pengkodean HTM, seperti &quote;. Saya menggabungkannya dengan WebUtility.HtmlDecodeuntuk itu (yang pada gilirannya tidak akan menghapus tag). Gunakan setelah penghapusan tag, karena dapat menulis ulang &gt;dan &lt;. MisalnyaWebUtility.HtmlDecode(Regex.Replace(myTextVariable, "<[^>]*(>|$)", string.Empty))
Yahoo Serius

@YahooSerious Terima kasih telah memberikan contoh. Ini bekerja dengan baik. Terima kasih.
SearchForKnowledge

Html Agility Pack adalah cara yang harus dilakukan, saya menggunakannya kembali di formulir web untuk menghapus seluruh halaman web untuk menggunakan konten!
Bojangles

3
@YahooSerious ini akan memungkinkan vektor XSS dalam & gt; skrip & lt; alert ("XXS"); & gt; / script & lt; Tidak akan dibersihkan oleh regex tetapi diubah oleh HtmlDecode menjadi <script> alert ("XXS"); </ script>

1
@Heather Poin yang sangat bagus. Penghapusan tag HTML harus dilakukan lagi setelah decoding entitas.
Tomalak

76

Unduh HTMLAgilityPack, sekarang! ;) Unduh LInk

Ini memungkinkan Anda memuat dan mengurai HTML. Kemudian Anda dapat menavigasi DOM dan mengekstrak nilai dalam dari semua atribut. Serius, ini akan memakan waktu maksimal sekitar 10 baris kode. Ini adalah salah satu pustaka .net gratis terbesar yang pernah ada.

Berikut ini contohnya:

            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;
            }

2
Anda bahkan dapat menanyakan setiap text()node, memangkas konten dan string. Bergabunglah dengan mereka yang memiliki spasi. IEnumerable<string> allText = doc.DocumentNode.SelectNodes("//text()").Select(n => n.InnerText.Trim())
jessehouwing

atau cukup gunakan doc.DocumentNode.InnerText, meskipun ini memiliki beberapa masalah dengan
penanganan

17
Mengapa if (doc == null)cek? Ini selalu salah, bukan?
avesse

67
Regex.Replace(htmlText, "<.*?>", string.Empty);

Sederhana dan menyenangkan. Terima kasih!
Tillito

5
Memiliki banyak masalah - tidak berurusan dengan atribut yang memiliki <atau> di dalamnya dan tidak berfungsi dengan baik dengan tag yang menjangkau lebih dari satu baris kecuali dijalankan dengan RegexOptions.SingleLine.
ChrisF

2
Tidaaaak, gunakan "<[^>] *>".
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

2
Tidak berfungsi untuk banyak kasus termasuk penggalan baris non-unix.
ChrisF

6

Saya telah memposting ini di forum asp.net, dan tampaknya masih menjadi salah satu solusi termudah di luar sana. Saya tidak menjamin ini yang tercepat atau paling efisien, tetapi cukup dapat diandalkan. Dalam .NET Anda dapat menggunakan objek Kontrol Web HTML itu sendiri. Yang perlu Anda lakukan hanyalah memasukkan string Anda ke dalam objek HTML sementara seperti DIV, lalu gunakan 'InnerText' bawaan untuk mengambil semua teks yang tidak ada di dalam tag. Lihat di bawah untuk contoh C # sederhana:


System.Web.UI.HtmlControls.HtmlGenericControl htmlDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("div");
htmlDiv.InnerHtml = htmlString;
String plainText = htmlDiv.InnerText;

ini sepertinya tidak berhasil, saya mengujinya dengan InnerHtml = "<b> foo </b>"; dan InnerText memiliki nilai "<b> foo </b>" :(
Axarydax

Jangan lakukan ini. Solusi ini menyuntikkan html yang tidak dikodekan langsung ke output. Ini akan membuat Anda terbuka lebar terhadap serangan Cross Site Scripting - Anda baru saja mengizinkan siapa saja yang dapat mengubah string html untuk menyuntikkan html dan javascript sembarang ke dalam aplikasi Anda!
saille

5

Saya telah menulis metode yang cukup cepat di c # yang mengalahkan Regex. Ini dihosting dalam artikel di CodeProject.

Keuntungannya adalah, di antara kinerja yang lebih baik kemampuan untuk mengganti entitas HTML bernama dan bernomor (seperti &amp;amp;dan &203;) dan penggantian blok komentar dan banyak lagi.

Silakan baca artikel terkait di CodeProject .

Terima kasih.


4

Bagi Anda yang tidak bisa menggunakan HtmlAgilityPack, pembaca XML .NETs adalah pilihan. Ini bisa gagal pada HTML yang diformat dengan baik jadi selalu tambahkan tangkapan dengan regx sebagai cadangan. Perhatikan ini BUKAN cepat, tetapi ini memberikan peluang bagus untuk langkah sekolah lama melalui debugging.

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;
    }

3
string result = Regex.Replace(anytext, @"<(.|\n)*?>", string.Empty);

1

Bagi mereka yang mengeluh tentang solusi Michael Tiptop yang tidak berfungsi, berikut adalah cara .Net4 + untuk melakukannya:

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;
    }
}

1
using System.Text.RegularExpressions;

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

0

Saya telah melihat solusi berbasis Regex yang disarankan di sini, dan mereka tidak membuat saya percaya diri kecuali dalam kasus yang paling sepele. Sebuah tanda kurung sudut dalam atribut adalah semua yang diperlukan untuk merusak, apalagi HTML yang salah format dari alam liar. Dan bagaimana dengan entitas seperti itu &amp;? Jika Anda ingin mengubah HTML menjadi teks biasa, Anda juga perlu mendekode entitas.

Jadi saya mengusulkan metode di bawah ini.

Menggunakan HtmlAgilityPack , metode ekstensi ini secara efisien menghapus semua tag HTML dari fragmen html. Juga menerjemahkan entitas HTML seperti &amp;. Mengembalikan hanya item teks bagian dalam, dengan baris baru di antara setiap item teks.

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();
}

Jika Anda benar-benar serius, kau ingin mengabaikan isi tag HTML tertentu juga ( <script>, <style>, <svg>, <head>, <object>datang ke pikiran!) Karena mereka mungkin tidak mengandung konten yang dapat dibaca dalam arti kita setelah. Apa yang Anda lakukan di sana akan bergantung pada keadaan Anda dan seberapa jauh Anda ingin melangkah, tetapi menggunakan HtmlAgilityPack akan sangat mudah untuk memasukkan tag yang dipilih ke daftar putih atau daftar hitam.

Jika Anda merender konten kembali ke halaman HTML, pastikan Anda memahami kerentanan XSS & cara mencegahnya - yaitu selalu menyandikan teks yang dimasukkan pengguna yang dirender kembali ke halaman HTML ( >menjadi &gt;dll.).


0

Untuk parameter kedua, yaitu pertahankan beberapa tag, Anda mungkin memerlukan beberapa kode seperti ini dengan menggunakan HTMLagilityPack:

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();
    }

Penjelasan lebih lanjut di halaman ini: http://nalgorithm.com/2015/11/20/strip-html-tags-of-an-html-in-c-strip_html-php-equivalent/


0

Anda juga dapat melakukan ini dengan AngleSharp yang merupakan alternatif untuk HtmlAgilityPack (bukan berarti HAP buruk). Ini lebih mudah digunakan daripada HAP untuk mengeluarkan teks dari sumber HTML.

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

Anda dapat melihat bagian fitur utama di mana mereka membuat kasus menjadi "lebih baik" daripada HAP. Saya pikir untuk sebagian besar, ini mungkin berlebihan untuk pertanyaan saat ini tetapi tetap saja, ini adalah alternatif yang menarik.


-4

Cukup gunakan string.StripHTML();


3
Seperti yang ditunjukkan @Serpiton, tidak ada metode seperti itu di BCL. Bisakah Anda menunjukkan penerapan metode ini atau memberikan penerapan Anda sendiri?
Sven Grosen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.