HTML etiketlerini ASP.NET'te bir dizeden nasıl çıkarabilirim?


123

ASP.NET kullanarak, HTML etiketlerini belirli bir dizeden nasıl güvenilir bir şekilde çıkarabilirim (ör. Regex kullanmadan)? PHP gibi bir şey arıyorum strip_tags.

Misal:

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

Çıktı:

"Merhaba"

Tekerleği yeniden icat etmemeye çalışıyorum ama şimdiye kadar ihtiyaçlarımı karşılayan bir şey bulamadım.


PHP strip_tags'in perde arkasında normal ifadeyi kullandığını düşünürdüm!
stevehipwell

10
@Daniel: çünkü regex bu konuda çok kötü, özellikle de iç içe geçmişseniz.
Joel Coehoorn

Hmm, PHP'nin Strip_Tags'i resmi notlarda ve yorumlarda özellikle güvenilir gibi görünmüyor: uk.php.net/strip_tags
Zhaph - Ben Duguid

Yanıtlar:


112

Sadece sıyırma ise bütün bir dize HTML etiketlerini, bu işleri güvenilir regex ile de. Değiştir:

<[^>]*(>|$)

genel olarak boş dizeyle. Daha sonra değiştirerek dizeyi normalleştirmeyi unutmayın:

[\s\r\n]+

tek bir boşlukla ve sonucu kırparak. İsteğe bağlı olarak, herhangi bir HTML karakter varlığını gerçek karakterlerle değiştirin.

Not :

  1. Bir sınırlama vardır: HTML ve XML >öznitelik değerlerine izin verir . Bu çözüm , bu tür değerlerle karşılaşıldığında bozuk işaretlemeyi döndürecektir.
  2. Çözüm teknik olarak güvenlidir, şu şekildedir: Sonuç hiçbir zaman siteler arası komut dosyası oluşturmak veya bir sayfa düzenini bozmak için kullanılabilecek hiçbir şey içermeyecektir. Çok temiz değil.
  3. HTML ve regex ile ilgili her şeyde olduğu gibi: Her koşulda doğru anlamanız gerekiyorsa uygun bir ayrıştırıcı
    kullanın .

52
İstenmese de, birçok okuyucunun HTM kodlamasını da çıkarmak isteyeceğini düşünüyorum &quote;. Bunun WebUtility.HtmlDecodeiçin onu birleştiriyorum (bu da etiketleri kaldırmayacak). Yeniden yazabileceğinden &gt;ve etiketini kaldırdıktan sonra kullanın &lt;. ÖrneğinWebUtility.HtmlDecode(Regex.Replace(myTextVariable, "<[^>]*(>|$)", string.Empty))
Yahoo Serious

@YahooSerious Örnek verdiğiniz için teşekkür ederiz. Bu harika çalışıyor. Teşekkür ederim.
SearchForKnowledge

Html Çeviklik Paketi gitmenin yoludur, içeriği kullanmak için tüm web sayfalarını çıkarmak için web formlarında geri döndüm!
Bojangles

3
@YahooSerious bu, bir XSS vektörünün & gt; komut dosyası & lt; alert ( "XXS"); ve gt; / komut dosyası & lt; Normal ifade tarafından sterilize edilmeyecek, ancak HtmlDecode tarafından <script> uyarısına ("XXS") dönüştürülecek; </ script>

1
@Heather Çok iyi bir nokta. Varlık kodu çözüldükten sonra HTML etiket sıyırma işleminin tekrar yapılması gerekir.
Tomalak

76

Git HTMLAgilityPack'i hemen indirin! ;) LInk'i İndir

Bu, HTML'yi yüklemenize ve ayrıştırmanıza olanak tanır. Ardından, DOM'da gezinebilir ve tüm özniteliklerin iç değerlerini çıkarabilirsiniz. Cidden, maksimumda yaklaşık 10 satır kod alacaktır. Piyasadaki en büyük ücretsiz .net kitaplıklarından biridir.

İşte bir örnek:

            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
Hatta her text()düğümü sorgulayabilir , içeriği ve dizeyi kırpabilirsiniz. boşluk olanlara katılın. IEnumerable<string> allText = doc.DocumentNode.SelectNodes("//text()").Select(n => n.InnerText.Trim())
jessehouwing

veya sadece doc.DocumentNode.InnerText kullanın, bunun beyaz boşlukların
işlenmesiyle

17
Neden if (doc == null)çek? Bu her zaman yanlıştır, öyle değil mi?
avesse

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

Basit ve güzel. Teşekkürler!
Tillito

5
Birçok sorunu vardır - içlerinde <veya> bulunan özniteliklerle uğraşmaz ve birlikte çalıştırılmadıkça birden fazla satıra yayılan etiketlerle iyi sonuç vermez RegexOptions.SingleLine.
ChrisF

2
Noooo, "<[^>] *>" kullanın.
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
Unix dışı satır kırılmaları dahil birçok durum için çalışmaz.
ChrisF

6

Bunu asp.net forumlarında yayınladım ve hala en kolay çözümlerden biri gibi görünüyor. En hızlı veya en verimli olduğunu garanti etmeyeceğim, ancak oldukça güvenilir. .NET'te HTML Web Kontrolü nesnelerini kullanabilirsiniz. Gerçekten yapmanız gereken tek şey, dizenizi DIV gibi geçici bir HTML nesnesine eklemek ve ardından etiketlerde bulunmayan tüm metni almak için yerleşik 'InnerText' özelliğini kullanmaktır. Basit bir C # örneği için aşağıya bakın:


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

bu işe yaramıyor gibi görünüyor, basit InnerHtml = "<b> foo </b>" ile test ettim; ve InnerText "<b> foo </b>"
değerine sahip

Bunu yapma. Bu çözüm, kodlanmamış html'yi doğrudan çıktıya enjekte eder. Bu sizi Siteler Arası Komut Dosyası saldırılarına tamamen açık hale getirir - html dizesini değiştirebilen herkesin uygulamanıza herhangi bir keyfi html ve javascript enjekte etmesine izin verdiniz!
2015 00:35

5

C # 'da Regex'i cehenneme çeviren oldukça hızlı bir yöntem yazdım. CodeProject ile ilgili bir makalede barındırılmaktadır .

Avantajları, daha iyi performansın yanı sıra, adlandırılmış ve numaralandırılmış HTML varlıklarını ( &amp;amp;ve gibi olanlar &203;) değiştirme ve yorum blokları değiştirme ve daha fazlasıdır.

Lütfen CodeProject ile ilgili makaleyi okuyun .

Teşekkür ederim.


4

HtmlAgilityPack'i kullanamayanlarınız için .NETs XML okuyucu bir seçenektir. Bu, iyi biçimlendirilmiş HTML'de başarısız olabilir, bu nedenle her zaman yedek olarak regx ile bir yakalama ekleyin. Bunun hızlı OLMADIĞINI unutmayın, ancak hata ayıklama yoluyla eski okul adımları için güzel bir fırsat sağlar.

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

Michael Tiptop'ın çözümünün işe yaramadığından şikayet edenler için, işte bunu yapmanın .Net4 + yolu:

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

Burada önerilen Regex tabanlı çözümlere baktım ve en önemsiz durumlar dışında beni hiçbir güvenle doldurmuyorlar. Bir öznitelikteki açılı ayraç, vahşi ortamdan yanlış biçimlendirilmiş HTML'yi bırakın, kırmak için gereken tek şeydir. Peki ya benzer varlıklar &amp;? HTML'yi düz metne dönüştürmek istiyorsanız, varlıkların da kodunu çözmeniz gerekir.

Bu yüzden aşağıdaki yöntemi öneriyorum.

HtmlAgilityPack'i kullanan bu uzantı yöntemi, tüm HTML etiketlerini bir html parçasından verimli bir şekilde çıkarır . Ayrıca gibi HTML varlıklarının kodunu çözer &amp;. Her metin öğesi arasında yeni bir satır olacak şekilde yalnızca iç metin öğelerini döndürür.

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

Eğer gerçekten ciddi iseniz, çok (bazı HTML etiketleri içeriğini göz ardı etmek isterdim <script>, <style>, <svg>, <head>, <object>muhtemelen biz peşinde anlamda okunabilir içeriğe sahip olmadığı için akla gelen!). Orada ne yapacağınız, koşullarınıza ve ne kadar ileri gitmek istediğinize bağlı olacaktır, ancak HtmlAgilityPack'i kullanarak, seçilen etiketleri beyaz listeye veya kara listeye almak oldukça önemsiz olacaktır.

Eğer bir HTML sayfasına içerik sırtını render iseniz, XSS açığı & anladığınızdan emin olun nasıl önleneceği - yani her zaman bir HTML sayfası (üzerine geri işlenen alır herhangi bir kullanıcı tarafından girilen metni kodlamak >olur &gt;vs).


0

İkinci parametre için, yani bazı etiketleri saklayın, HTMLagilityPack kullanarak bunun gibi bir koda ihtiyacınız olabilir:

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

Bu sayfada daha fazla açıklama: http://nalgorithm.com/2015/11/20/strip-html-tags-of-an-html-in-c-strip_html-php-equivalent/


0

Bunu, HtmlAgilityPack'e alternatif olan AngleSharp ile de yapabilirsiniz (HAP kötü değildir). Metni bir HTML kaynağından almak için kullanmak HAP'tan daha kolaydır.

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

HAP'tan "daha iyi" olduklarını iddia ettikleri temel özellikler bölümüne göz atabilirsiniz . Çoğunlukla, mevcut soru için muhtemelen aşırı olduğunu düşünüyorum ama yine de ilginç bir alternatif.


-4

Basitçe kullan string.StripHTML();


3
@Serpiton'ın da işaret ettiği gibi BCL'de böyle bir yöntem yok. Bu yöntemin bir uygulamasını işaret edebilir misiniz veya kendinizinkini sağlayabilir misiniz?
Sven Grosen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.