Usuń tagi HTML z ciągu znaków, w tym & nbsp w C #

83

Jak mogę usunąć wszystkie tagi HTML, w tym & nbsp, używając wyrażenia regularnego w C #. Wygląda jak mój sznurek

  "<div>hello</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div>"
rampuriyaaa
źródło
9
Nie używaj wyrażenia regularnego, sprawdź HTML Agility Pack. stackoverflow.com/questions/846994/how-to-use-html-agility-pack
Tim
Dzięki Tim, ale aplikacja jest dość duża i nienaruszona, dodanie lub pobranie pakietu agility HTML nie zadziała.
rampuriyaaa

Odpowiedzi:

198

Jeśli nie możesz użyć rozwiązania zorientowanego na parser HTML do odfiltrowania tagów, oto proste wyrażenie regularne.

string noHTML = Regex.Replace(inputHTML, @"<[^>]+>|&nbsp;", "").Trim();

Najlepiej byłoby, gdybyśmy ponownie przeszli przez filtr wyrażeń regularnych, który zajmuje się wieloma spacjami jako

string noHTMLNormalised = Regex.Replace(noHTML, @"\s{2,}", " ");
Ravi K Thapliyal
źródło
Nie testowałem jeszcze tego tak często, jak będę musiał, ale zadziałało lepiej, niż się spodziewałem. Opublikuję metodę, którą napisałem poniżej.
Don Rolling
Leniwy mecz ( <[^>]+?>zgodnie z @David S.) może przyspieszyć to trochę, ale właśnie użyłem tego rozwiązania w projekcie na żywo - bardzo szczęśliwy +1 :)
Gone Coding
Regex.Replace (inputHTML, @ "<[^>] +> | & nbsp | \ n;", "") .Trim (); \ n nie zostanie usunięty
Mahesh Malpani
3
Regex.Replace(inputHTML, @"<[^>]+>|&nbsp;", " ")
Poleciłbym
2
@Tauseef Jeśli użyjesz spacji w pierwszym wywołaniu zamiany, możesz w końcu zostawić spacje tam, gdzie nie było ich w oryginalnym wejściu. Powiedz, że otrzymujesz Sound<b>Cloud</b>jako wkład; skończysz z tym Sound Cloud, że powinien zostać usunięty, SoundCloudponieważ tak jest wyświetlany w HTML.
Ravi K Thapliyal
31

Wziąłem kod @Ravi Thapliyal i stworzyłem metodę: jest prosta i może nie wyczyścić wszystkiego, ale jak dotąd robi to, czego potrzebuję.

public static string ScrubHtml(string value) {
    var step1 = Regex.Replace(value, @"<[^>]+>|&nbsp;", "").Trim();
    var step2 = Regex.Replace(step1, @"\s{2,}", " ");
    return step2;
}
Don Rolling
źródło
16

Używam tej funkcji od jakiegoś czasu. Usuwa prawie każdy niechlujny kod HTML, który możesz na niego rzucić, i pozostawia tekst nietknięty.

        private static readonly Regex _tags_ = new Regex(@"<[^>]+?>", RegexOptions.Multiline | RegexOptions.Compiled);

        //add characters that are should not be removed to this regex
        private static readonly Regex _notOkCharacter_ = new Regex(@"[^\w;&#@.:/\\?=|%!() -]", RegexOptions.Compiled);

        public static String UnHtml(String html)
        {
            html = HttpUtility.UrlDecode(html);
            html = HttpUtility.HtmlDecode(html);

            html = RemoveTag(html, "<!--", "-->");
            html = RemoveTag(html, "<script", "</script>");
            html = RemoveTag(html, "<style", "</style>");

            //replace matches of these regexes with space
            html = _tags_.Replace(html, " ");
            html = _notOkCharacter_.Replace(html, " ");
            html = SingleSpacedTrim(html);

            return html;
        }

        private static String RemoveTag(String html, String startTag, String endTag)
        {
            Boolean bAgain;
            do
            {
                bAgain = false;
                Int32 startTagPos = html.IndexOf(startTag, 0, StringComparison.CurrentCultureIgnoreCase);
                if (startTagPos < 0)
                    continue;
                Int32 endTagPos = html.IndexOf(endTag, startTagPos + 1, StringComparison.CurrentCultureIgnoreCase);
                if (endTagPos <= startTagPos)
                    continue;
                html = html.Remove(startTagPos, endTagPos - startTagPos + endTag.Length);
                bAgain = true;
            } while (bAgain);
            return html;
        }

        private static String SingleSpacedTrim(String inString)
        {
            StringBuilder sb = new StringBuilder();
            Boolean inBlanks = false;
            foreach (Char c in inString)
            {
                switch (c)
                {
                    case '\r':
                    case '\n':
                    case '\t':
                    case ' ':
                        if (!inBlanks)
                        {
                            inBlanks = true;
                            sb.Append(' ');
                        }   
                        continue;
                    default:
                        inBlanks = false;
                        sb.Append(c);
                        break;
                }
            }
            return sb.ToString().Trim();
        }
David S.
źródło
Dla potwierdzenia: funkcja SingleSpacedTrim () robi to samo, co string noHTMLNormalised = Regex.Replace (noHTML, @ "\ s {2,}", ""); z odpowiedzi Raviego Thapliyala?
Jimmy
@Jimmy, o ile widzę, to wyrażenie regularne nie przechwytuje pojedynczych tabulatorów ani znaków nowej linii, jak robi to SingleSpacedTrim (). Może to być jednak pożądany efekt, w takim przypadku po prostu usuń skrzynki w razie potrzeby.
David S.
Fajnie, ale wydaje się, że zastępuje pojedyncze i podwójne cudzysłowy spacjami, chociaż nie ma ich na liście „ notOkCharacter ”, czy czegoś tam brakuje? Czy ta część metod dekodowania / kodowania jest wywoływana na początku? Co byłoby konieczne, aby zachować te postacie w stanie nienaruszonym?
vm370,
4
var noHtml = Regex.Replace(inputHTML, @"<[^>]*(>|$)|&nbsp;|&zwnj;|&raquo;|&laquo;", string.Empty).Trim();
MRP
źródło
1

Użyłem kodu @RaviThapliyal & @Don Rolling, ale dokonałem niewielkiej modyfikacji. Ponieważ zamieniamy & nbsp na pusty ciąg, ale zamiast tego & nbsp należy zastąpić spacją, dlatego dodano dodatkowy krok. U mnie zadziałało jak urok.

public static string FormatString(string value) {
    var step1 = Regex.Replace(value, @"<[^>]+>", "").Trim();
    var step2 = Regex.Replace(step1, @"&nbsp;", " ");
    var step3 = Regex.Replace(step2, @"\s{2,}", " ");
    return step3;
}

Użyto & nbps bez średnika, ponieważ było formatowane przez przepełnienie stosu.

Sabique A Khan
źródło
0

to:

(<.+?> | &nbsp;)

będzie pasować do dowolnego tagu lub &nbsp;

string regex = @"(<.+?>|&nbsp;)";
var x = Regex.Replace(originalString, regex, "").Trim();

następnie x = hello

Jonesopolis
źródło
0

Oczyszczanie dokumentu HTML wiąże się z wieloma trudnymi sprawami. Ten pakiet może pomóc: https://github.com/mganss/HtmlSanitizer

Ehsan88
źródło
Myślę, że to bardziej przeciwko atakom XSS niż normalizacja html
Revious,
1
@Revious Myślę, że masz rację. Może moja odpowiedź nie jest zbytnio związana z pytaniem OP, ponieważ nie wspomnieli o celu usunięcia tagów HTML. Ale jeśli celem jest zapobieganie atakom, jak to ma miejsce w wielu przypadkach, lepszym podejściem może być użycie już opracowanego środka odkażającego. A tak przy okazji, nie wiem, jakie jest znaczenie normalizacji html .
Ehsan88
0

HTML jest w swojej podstawowej formie po prostu XML. Możesz przeanalizować tekst w obiekcie XmlDocument i wywołać InnerText w elemencie głównym, aby wyodrębnić tekst. Spowoduje to usunięcie wszystkich znaczników HTML w dowolnej formie, a także obsługę znaków specjalnych, takich jak & lt; & nbsp; wszystko za jednym zamachem.

nivs1978
źródło