Jak przekonwertować HTML na zwykły tekst?

99

Mam fragmenty kodu HTML zapisane w tabeli. Nie całe strony, brak tagów lub tym podobne, tylko podstawowe formatowanie.

Chciałbym móc wyświetlić ten kod HTML jako sam tekst, bez formatowania , na danej stronie (właściwie tylko pierwsze 30-50 znaków, ale to jest łatwe).

Jak umieścić „tekst” w tym html w ciągu jako zwykły tekst?

Więc ten fragment kodu.

<b>Hello World.</b><br/><p><i>Is there anyone out there?</i><p>

Staje się:

Witaj świecie. Czy jest tam ktoś?

Stuart Helwig
źródło
Możesz użyć SgmlReader. code.msdn.microsoft.com/SgmlReader
Leonardo Herrera
Na blackbeltcoder.com/Articles/strings/convert-html-to-text znajduje się dość prosty i nieskomplikowany kod do konwersji HTML na zwykły tekst .
Jonathan Wood
To była właściwa odpowiedź na to, czego potrzebowałem - dzięki!
Shaul Behr
Istnieje kilka dobrych sugestii od W3C tutaj: w3.org/Tools/html2things.html
Rich
4
Jak można oznaczyć pytanie jako duplikat pytania zadanego 6 miesięcy później? Wydaje się trochę zacofany ...
Stuart Helwig

Odpowiedzi:

28

Jeśli mówisz o usuwaniu tagów, jest to stosunkowo proste, jeśli nie musisz się martwić takimi rzeczami, jak <script>tagi. Jeśli wszystko, co musisz zrobić, to wyświetlić tekst bez tagów, możesz to zrobić za pomocą wyrażenia regularnego:

<[^>]*>

Jeśli musisz martwić się o <script>znaczniki i tym podobne, będziesz potrzebować czegoś mocniejszego niż wyrażenia regularne, ponieważ musisz śledzić stan, coś bardziej jak gramatyka bez kontekstu (CFG). Chociaż możesz być w stanie to osiągnąć za pomocą `` od lewej do prawej '' lub niechcianego dopasowania.

Jeśli potrafisz używać wyrażeń regularnych, istnieje wiele stron internetowych zawierających dobre informacje:

Jeśli potrzebujesz bardziej złożonego zachowania CFG, sugerowałbym użycie narzędzia innej firmy, niestety nie znam dobrego, które mógłbym polecić.

vfilby
źródło
3
Musisz także martwić się> wartościami atrybutów, komentarzami, PI / CDATA w XML i różnymi typowymi błędami w starszym HTMLu. Ogólnie rzecz biorąc, [X] [HT] ML nie podlega analizowaniu za pomocą wyrażeń regularnych.
bobince
11
To okropna metoda. Prawidłowym sposobem jest przeanalizowanie kodu HTML za pomocą biblioteki lib i przejście przez domenę dom, wyświetlając tylko zawartość z białej listy.
usr
2
@usr: Część, do której się odnosisz, jest częścią odpowiedzi dotyczącą CFG. Regex może być używany do szybkiego i brudnego usuwania tagów, ma swoje wady, ale jest szybki i łatwy. Aby uzyskać bardziej skomplikowaną analizę, użyj narzędzia opartego na CFG (w twoim języku biblioteki, która generuje DOM). Nie wykonałem testów, ale założyłem się, że parsowanie DOM jest wolniejsze niż usuwanie wyrażeń regularnych, na wypadek, gdyby trzeba było wziąć pod uwagę wydajność.
vfilby
1
@vfilby, pierwszym atakiem, który przychodzi na myśl, jest napisanie „<div id = \” ”(składnia ciągu C #). Zwróć uwagę na brakujące cudzysłowy końcowe i brakujący nawias zamykający. Wydaje mi się, że to zmyli przeglądarkę i zachwieje strukturę tagu. myślisz o tym ataku? Czy możesz być pewien, że to nigdy nie zadziała? Nasty.
usr
1
@vfilby, nie ma znaczenia, czy biblioteka analizująca jest zdezorientowana, czy nie. Wszystko, co musisz zrobić, to wziąć z niego DOM (w ogóle dowolny DOM) i wyprowadzić tylko komponenty z białej listy. Jest to zawsze bezpieczne, bez względu na to, jak wygląda przeanalizowany DOM. Podałem też wiele przykładów, w których „prosta” metoda nie pozwala usunąć tagów.
usr
96

Darmowy i otwarty HtmlAgilityPack ma w jednej ze swoich próbek metodę, która konwertuje z HTML do zwykłego tekstu.

var plainText = HtmlUtilities.ConvertToPlainText(string html);

Podaj mu ciąg HTML, taki jak

<b>hello, <i>world!</i></b>

Otrzymasz wynik w postaci zwykłego tekstu, na przykład:

hello world!
Judah Gabriel Himango
źródło
10
Korzystałem już wcześniej z HtmlAgilityPack, ale nie widzę żadnego odniesienia do ConvertToPlainText. Czy możesz mi powiedzieć, gdzie mogę to znaleźć?
horatio
8
Horatio, jest on zawarty w jednej z próbek dostarczanych z pakietem HtmlAgilityPack: htmlagilitypack.codeplex.com/sourcecontrol/changeset/view/…
Judah Gabriel Himango
5
Właściwie w Pakiecie Zwinności nie ma na to wbudowanej metody. To, do czego się podłączyłeś, to przykład, który używa pakietu Agility Pack do przechodzenia po drzewie węzłów, usuwania scripti styletagowania oraz zapisywania wewnętrznego tekstu innych elementów w ciągu wyjściowym. Wątpię, czy przeszedł wiele testów z danymi wejściowymi ze świata rzeczywistego.
Lou
3
Czy ktoś może podać działający kod, w przeciwieństwie do linków do próbek, które muszą zostać doposażone, aby działały poprawnie?
Eric K.
6
Próbkę można teraz znaleźć tutaj: github.com/ceee/ReadSharp/blob/master/ReadSharp/ ...
StuartQ
51

Nie mogłem użyć HtmlAgilityPack, więc napisałem dla siebie drugie najlepsze rozwiązanie

private static string HtmlToPlainText(string html)
{
    const string tagWhiteSpace = @"(>|$)(\W|\n|\r)+<";//matches one or more (white space or line breaks) between '>' and '<'
    const string stripFormatting = @"<[^>]*(>|$)";//match any character between '<' and '>', even when end tag is missing
    const string lineBreak = @"<(br|BR)\s{0,1}\/{0,1}>";//matches: <br>,<br/>,<br />,<BR>,<BR/>,<BR />
    var lineBreakRegex = new Regex(lineBreak, RegexOptions.Multiline);
    var stripFormattingRegex = new Regex(stripFormatting, RegexOptions.Multiline);
    var tagWhiteSpaceRegex = new Regex(tagWhiteSpace, RegexOptions.Multiline);

    var text = html;
    //Decode html specific characters
    text = System.Net.WebUtility.HtmlDecode(text); 
    //Remove tag whitespace/line breaks
    text = tagWhiteSpaceRegex.Replace(text, "><");
    //Replace <br /> with line breaks
    text = lineBreakRegex.Replace(text, Environment.NewLine);
    //Strip formatting
    text = stripFormattingRegex.Replace(text, string.Empty);

    return text;
}
Ben Anderson
źródło
2
& lt; blabla & gt; został przeanalizowany, więc przeniosłem tekst = System.Net.WebUtility.HtmlDecode (tekst); do końca metody
Luuk,
1
To było świetne, dodałem też kondensator wieloprzestrzenny, ponieważ kod HTML mógł zostać wygenerowany z CMS: var spaceRegex = new Regex ("[] {2,}", RegexOptions.None);
Enkode
Czasami w kodzie html jest nowa linia programisty (nowej linii nie widać w komentarzu, więc pokazuję ją jako [nowa linia], na przykład: <br> I [nowa linia] tęsknię za [nową linią] ty <br >, Więc ma pokazać: „Tęsknię za tobą”, ale pokazuje, że [nowa linia] tęsknię za [nową linią] za tobą. To sprawia, że ​​zwykły tekst wygląda
bolesnie
@ 123iamking możesz użyć tego przed tekstem powrotu; : text.Replace ("[nowa linia]", "\ n");
Eslam Badawy,
Używałem tego i zdałem sobie sprawę, że czasami pozostawia znak „>” na początku napisów. Drugie rozwiązanie polegające na zastosowaniu wyrażenia regularnego <[^>] *> działa dobrze.
Etienne Charland
20

HTTPUtility.HTMLEncode()ma na celu obsługę kodowania znaczników HTML jako ciągów. Zajmuje się całym ciężkim podnoszeniem za Ciebie. Z dokumentacji MSDN :

Jeśli w strumieniu HTTP przekazywane są znaki, takie jak spacje i znaki interpunkcyjne, mogą zostać błędnie zinterpretowane po stronie odbiorczej. Kodowanie HTML konwertuje znaki, które nie są dozwolone w HTML, na odpowiedniki jednostek znakowych; Dekodowanie HTML odwraca kodowanie. Na przykład po osadzeniu w bloku tekstu znaki <i >, są kodowane jako &lt;i &gt;dla transmisji HTTP.

HTTPUtility.HTMLEncode()metoda, szczegółowo opisana tutaj :

public static void HtmlEncode(
  string s,
  TextWriter output
)

Stosowanie:

String TestString = "This is a <Test String>.";
StringWriter writer = new StringWriter();
Server.HtmlEncode(TestString, writer);
String EncodedString = writer.ToString();
George Stocker
źródło
Naprawdę dobra odpowiedź, dzięki George, podkreślała również, jak słabo zadałem pytanie za pierwszym razem. Przepraszam.
Stuart Helwig
Pakiet Agility html jest przestarzały i nie obsługuje html5
abzarak
10

Aby dodać do odpowiedzi vfilby, możesz po prostu wykonać zamianę wyrażenia regularnego w swoim kodzie; nie są potrzebne żadne nowe zajęcia. Na wypadek, gdyby inni nowicjusze, tacy jak ja, natknęli się na to pytanie.

using System.Text.RegularExpressions;

Następnie...

private string StripHtml(string source)
{
        string output;

        //get rid of HTML tags
        output = Regex.Replace(source, "<[^>]*>", string.Empty);

        //get rid of multiple blank lines
        output = Regex.Replace(output, @"^\s*$\n", string.Empty, RegexOptions.Multiline);

        return output;
}
WEFX
źródło
19
NIEDOBRZE! Można to oszukać, aby zawierał skrypt, pomijając zamykający nawias ostry. GUYS, nigdy nie rób czarnych list. Nie możesz oczyścić danych wejściowych przez dodanie do czarnej listy. To jest takie złe.
usr
7

Trzyetapowy proces konwersji HTML na zwykły tekst

Najpierw musisz zainstalować pakiet Nuget dla HtmlAgilityPack Drugi Utwórz tę klasę

public class HtmlToText
{
    public HtmlToText()
    {
    }

    public string Convert(string path)
    {
        HtmlDocument doc = new HtmlDocument();
        doc.Load(path);

        StringWriter sw = new StringWriter();
        ConvertTo(doc.DocumentNode, sw);
        sw.Flush();
        return sw.ToString();
    }

    public string ConvertHtml(string html)
    {
        HtmlDocument doc = new HtmlDocument();
        doc.LoadHtml(html);

        StringWriter sw = new StringWriter();
        ConvertTo(doc.DocumentNode, sw);
        sw.Flush();
        return sw.ToString();
    }

    private void ConvertContentTo(HtmlNode node, TextWriter outText)
    {
        foreach(HtmlNode subnode in node.ChildNodes)
        {
            ConvertTo(subnode, outText);
        }
    }

    public void ConvertTo(HtmlNode node, TextWriter outText)
    {
        string html;
        switch(node.NodeType)
        {
            case HtmlNodeType.Comment:
                // don't output comments
                break;

            case HtmlNodeType.Document:
                ConvertContentTo(node, outText);
                break;

            case HtmlNodeType.Text:
                // script and style must not be output
                string parentName = node.ParentNode.Name;
                if ((parentName == "script") || (parentName == "style"))
                    break;

                // get text
                html = ((HtmlTextNode)node).Text;

                // is it in fact a special closing node output as text?
                if (HtmlNode.IsOverlappedClosingElement(html))
                    break;

                // check the text is meaningful and not a bunch of whitespaces
                if (html.Trim().Length > 0)
                {
                    outText.Write(HtmlEntity.DeEntitize(html));
                }
                break;

            case HtmlNodeType.Element:
                switch(node.Name)
                {
                    case "p":
                        // treat paragraphs as crlf
                        outText.Write("\r\n");
                        break;
                }

                if (node.HasChildNodes)
                {
                    ConvertContentTo(node, outText);
                }
                break;
        }
    }
}

Używając powyższej klasy w odniesieniu do odpowiedzi Judy Himango

Po trzecie, musisz utworzyć obiekt powyższej klasy i użyć ConvertHtml(HTMLContent)metody do konwersji HTML na zwykły tekst zamiastConvertToPlainText(string html);

HtmlToText htt=new HtmlToText();
var plainText = htt.ConvertHtml(HTMLContent);
Abdulqadir_WDDN
źródło
czy mogę pominąć konwersję linków w html. muszę zachować linki w html podczas konwersji na tekst?
coder771
6

Ma ograniczenie polegające na tym, że nie zwija długich białych znaków w wierszu, ale jest zdecydowanie przenośny i szanuje układ jak przeglądarka internetowa.

static string HtmlToPlainText(string html) {
  string buf;
  string block = "address|article|aside|blockquote|canvas|dd|div|dl|dt|" +
    "fieldset|figcaption|figure|footer|form|h\\d|header|hr|li|main|nav|" +
    "noscript|ol|output|p|pre|section|table|tfoot|ul|video";

  string patNestedBlock = $"(\\s*?</?({block})[^>]*?>)+\\s*";
  buf = Regex.Replace(html, patNestedBlock, "\n", RegexOptions.IgnoreCase);

  // Replace br tag to newline.
  buf = Regex.Replace(buf, @"<(br)[^>]*>", "\n", RegexOptions.IgnoreCase);

  // (Optional) remove styles and scripts.
  buf = Regex.Replace(buf, @"<(script|style)[^>]*?>.*?</\1>", "", RegexOptions.Singleline);

  // Remove all tags.
  buf = Regex.Replace(buf, @"<[^>]*(>|$)", "", RegexOptions.Multiline);

  // Replace HTML entities.
  buf = WebUtility.HtmlDecode(buf);
  return buf;
}
jeiea
źródło
4

Nie ma metody o nazwie „ConvertToPlainText” w HtmlAgilityPack, ale można przekonwertować ciąg html na ciąg CLEAR za pomocą:

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlString);
var textString = doc.DocumentNode.InnerText;
Regex.Replace(textString , @"<(.|n)*?>", string.Empty).Replace("&nbsp", "");

To działa dla mnie. ALE NIE ZNAJDUJĘ METODY O NAZWIE „ConvertToPlainText” W „HtmlAgilityPack”.

Amina
źródło
3

Myślę, że najłatwiejszym sposobem jest utworzenie metody rozszerzenia `` ciągów '' (w oparciu o sugestie użytkownika Richarda):

using System;
using System.Text.RegularExpressions;

public static class StringHelpers
{
    public static string StripHTML(this string HTMLText)
        {
            var reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase);
            return reg.Replace(HTMLText, "");
        }
}

Następnie po prostu użyj tej metody rozszerzenia na dowolnej zmiennej „łańcuchowej” w swoim programie:

var yourHtmlString = "<div class=\"someclass\"><h2>yourHtmlText</h2></span>";
var yourTextString = yourHtmlString.StripHTML();

Używam tej metody rozszerzenia, aby przekonwertować komentarze w formacie HTML na zwykły tekst, aby był poprawnie wyświetlany w raporcie kryształu i działa idealnie!

mikhail-t
źródło
3

Najprostszy sposób, jaki znalazłem:

HtmlFilter.ConvertToPlainText(html);

Klasa HtmlFilter znajduje się w Microsoft.TeamFoundation.WorkItemTracking.Controls.dll

Bibliotekę dll można znaleźć w następującym folderze:% ProgramFiles% \ Common Files \ microsoft shared \ Team Foundation Server \ 14.0 \

W VS 2015 dll wymaga również odwołania do Microsoft.TeamFoundation.WorkItemTracking.Common.dll, znajdującego się w tym samym folderze.

Roman O
źródło
czy dba o tagi skryptów i czy formatuje jako pogrubioną kursywę itp.?
Samra
Wprowadzenie zależności zespołu do konwersji html na zwykły tekst, bardzo wątpliwa ...
ViRuSTriNiTy
2

Jeśli masz dane zawierające znaczniki HTML i chcesz je wyświetlić, aby osoba mogła ZOBACZYĆ tagi, użyj HttpServerUtility :: HtmlEncode.

Jeśli masz dane zawierające tagi HTML i chcesz, aby użytkownik zobaczył renderowane tagi, wyświetl tekst w niezmienionej postaci. Jeśli tekst przedstawia całą stronę internetową, użyj do tego ramek IFRAME.

Jeśli masz dane zawierające znaczniki HTML i chcesz je usunąć i po prostu wyświetlić niesformatowany tekst, użyj wyrażenia regularnego.

Corey Trager
źródło
w php jest funkcja o nazwie striptags () może masz coś podobnego
markus
"użyj wyrażenia regularnego" NIE! To byłaby czarna lista. Możesz być bezpieczny tylko robiąc białe listy. Na przykład, czy pamiętasz, że atrybut stylu może zawierać „background: url ('javascript: ...');”? oczywiście, że nie, ja też nie. Dlatego czarna lista nie działa.
usr
2

Miałem podobny problem i znalazłem najlepsze rozwiązanie. Poniższy kod u mnie działa idealnie.

  private string ConvertHtml_Totext(string source)
    {
     try
      {
      string result;

    // Remove HTML Development formatting
    // Replace line breaks with space
    // because browsers inserts space
    result = source.Replace("\r", " ");
    // Replace line breaks with space
    // because browsers inserts space
    result = result.Replace("\n", " ");
    // Remove step-formatting
    result = result.Replace("\t", string.Empty);
    // Remove repeating spaces because browsers ignore them
    result = System.Text.RegularExpressions.Regex.Replace(result,
                                                          @"( )+", " ");

    // Remove the header (prepare first by clearing attributes)
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*head([^>])*>","<head>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"(<( )*(/)( )*head( )*>)","</head>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(<head>).*(</head>)",string.Empty,
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // remove all scripts (prepare first by clearing attributes)
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*script([^>])*>","<script>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"(<( )*(/)( )*script( )*>)","</script>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    //result = System.Text.RegularExpressions.Regex.Replace(result,
    //         @"(<script>)([^(<script>\.</script>)])*(</script>)",
    //         string.Empty,
    //         System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"(<script>).*(</script>)",string.Empty,
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // remove all styles (prepare first by clearing attributes)
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*style([^>])*>","<style>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"(<( )*(/)( )*style( )*>)","</style>",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(<style>).*(</style>)",string.Empty,
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // insert tabs in spaces of <td> tags
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*td([^>])*>","\t",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // insert line breaks in places of <BR> and <LI> tags
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*br( )*>","\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*li( )*>","\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // insert line paragraphs (double line breaks) in place
    // if <P>, <DIV> and <TR> tags
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*div([^>])*>","\r\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*tr([^>])*>","\r\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<( )*p([^>])*>","\r\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // Remove remaining tags like <a>, links, images,
    // comments etc - anything that's enclosed inside < >
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"<[^>]*>",string.Empty,
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // replace special characters:
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @" "," ",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&bull;"," * ",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&lsaquo;","<",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&rsaquo;",">",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&trade;","(tm)",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&frasl;","/",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&lt;","<",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&gt;",">",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&copy;","(c)",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&reg;","(r)",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    // Remove all others. More can be added, see
    // http://hotwired.lycos.com/webmonkey/reference/special_characters/
    result = System.Text.RegularExpressions.Regex.Replace(result,
             @"&(.{2,6});", string.Empty,
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // for testing
    //System.Text.RegularExpressions.Regex.Replace(result,
    //       this.txtRegex.Text,string.Empty,
    //       System.Text.RegularExpressions.RegexOptions.IgnoreCase);

    // make line breaking consistent
    result = result.Replace("\n", "\r");

    // Remove extra line breaks and tabs:
    // replace over 2 breaks with 2 and over 4 tabs with 4.
    // Prepare first to remove any whitespaces in between
    // the escaped characters and remove redundant tabs in between line breaks
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\r)( )+(\r)","\r\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\t)( )+(\t)","\t\t",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\t)( )+(\r)","\t\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\r)( )+(\t)","\r\t",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    // Remove redundant tabs
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\r)(\t)+(\r)","\r\r",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    // Remove multiple tabs following a line break with just one tab
    result = System.Text.RegularExpressions.Regex.Replace(result,
             "(\r)(\t)+","\r\t",
             System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    // Initial replacement target string for line breaks
    string breaks = "\r\r\r";
    // Initial replacement target string for tabs
    string tabs = "\t\t\t\t\t";
    for (int index=0; index<result.Length; index++)
    {
        result = result.Replace(breaks, "\r\r");
        result = result.Replace(tabs, "\t\t\t\t");
        breaks = breaks + "\r";
        tabs = tabs + "\t";
    }

    // That's it.
    return result;
}
catch
{
    MessageBox.Show("Error");
    return source;
}

}

Znaki ucieczki, takie jak \ n i \ r, musiały zostać najpierw usunięte, ponieważ powodują, że wyrażenia regularne przestają działać zgodnie z oczekiwaniami.

Ponadto, aby ciąg wynikowy wyświetlał się poprawnie w polu tekstowym, może być konieczne podzielenie go i ustawienie właściwości Lines pola tekstowego zamiast przypisywania do właściwości Text.

this.txtResult.Lines = StripHTML (this.txtSource.Text) .Split ("\ r" .ToCharArray ());

Źródło: https://www.codeproject.com/Articles/11902/Convert-HTML-to-Plain-Text-2

LakshmiSarada
źródło
0

Zależy od tego, co rozumiesz przez „html”. Najbardziej złożonym przypadkiem byłyby kompletne strony internetowe. Jest to również najłatwiejsze w obsłudze, ponieważ możesz użyć przeglądarki internetowej w trybie tekstowym. Zobacz artykuł Wikipedii zawierający listę przeglądarek internetowych, w tym przeglądarek w trybie tekstowym. Ryś jest prawdopodobnie najbardziej znanym, ale jeden z pozostałych może być lepszy dla twoich potrzeb.

mpez0
źródło
jak powiedział „Mam fragmenty kodu HTML zapisane w tabeli”
M at
0

Oto moje rozwiązanie:

public string StripHTML(string html)
{
    var regex = new Regex("<[^>]+>", RegexOptions.IgnoreCase);
    return System.Web.HttpUtility.HtmlDecode((regex.Replace(html, "")));
}

Przykład:

StripHTML("<p class='test' style='color:red;'>Here is my solution:</p>");
// output -> Here is my solution:
Mehdi Dehghani
źródło
0

Miałem to samo pytanie, tylko mój html miał prosty, znany układ, taki jak:

<DIV><P>abc</P><P>def</P></DIV>

Skończyło się na tym, że użyłem prostego kodu:

string.Join (Environment.NewLine, XDocument.Parse (html).Root.Elements ().Select (el => el.Value))

Które wyjścia:

abc
def
Karlas
źródło
0

Nie napisałem, ale użyłem:

using HtmlAgilityPack;
using System;
using System.IO;
using System.Text.RegularExpressions;

namespace foo {
  //small but important modification to class https://github.com/zzzprojects/html-agility-pack/blob/master/src/Samples/Html2Txt/HtmlConvert.cs
  public static class HtmlToText {

    public static string Convert(string path) {
      HtmlDocument doc = new HtmlDocument();
      doc.Load(path);
      return ConvertDoc(doc);
    }

    public static string ConvertHtml(string html) {
      HtmlDocument doc = new HtmlDocument();
      doc.LoadHtml(html);
      return ConvertDoc(doc);
    }

    public static string ConvertDoc(HtmlDocument doc) {
      using (StringWriter sw = new StringWriter()) {
        ConvertTo(doc.DocumentNode, sw);
        sw.Flush();
        return sw.ToString();
      }
    }

    internal static void ConvertContentTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) {
      foreach (HtmlNode subnode in node.ChildNodes) {
        ConvertTo(subnode, outText, textInfo);
      }
    }
    public static void ConvertTo(HtmlNode node, TextWriter outText) {
      ConvertTo(node, outText, new PreceedingDomTextInfo(false));
    }
    internal static void ConvertTo(HtmlNode node, TextWriter outText, PreceedingDomTextInfo textInfo) {
      string html;
      switch (node.NodeType) {
        case HtmlNodeType.Comment:
          // don't output comments
          break;
        case HtmlNodeType.Document:
          ConvertContentTo(node, outText, textInfo);
          break;
        case HtmlNodeType.Text:
          // script and style must not be output
          string parentName = node.ParentNode.Name;
          if ((parentName == "script") || (parentName == "style")) {
            break;
          }
          // get text
          html = ((HtmlTextNode)node).Text;
          // is it in fact a special closing node output as text?
          if (HtmlNode.IsOverlappedClosingElement(html)) {
            break;
          }
          // check the text is meaningful and not a bunch of whitespaces
          if (html.Length == 0) {
            break;
          }
          if (!textInfo.WritePrecedingWhiteSpace || textInfo.LastCharWasSpace) {
            html = html.TrimStart();
            if (html.Length == 0) { break; }
            textInfo.IsFirstTextOfDocWritten.Value = textInfo.WritePrecedingWhiteSpace = true;
          }
          outText.Write(HtmlEntity.DeEntitize(Regex.Replace(html.TrimEnd(), @"\s{2,}", " ")));
          if (textInfo.LastCharWasSpace = char.IsWhiteSpace(html[html.Length - 1])) {
            outText.Write(' ');
          }
          break;
        case HtmlNodeType.Element:
          string endElementString = null;
          bool isInline;
          bool skip = false;
          int listIndex = 0;
          switch (node.Name) {
            case "nav":
              skip = true;
              isInline = false;
              break;
            case "body":
            case "section":
            case "article":
            case "aside":
            case "h1":
            case "h2":
            case "header":
            case "footer":
            case "address":
            case "main":
            case "div":
            case "p": // stylistic - adjust as you tend to use
              if (textInfo.IsFirstTextOfDocWritten) {
                outText.Write("\r\n");
              }
              endElementString = "\r\n";
              isInline = false;
              break;
            case "br":
              outText.Write("\r\n");
              skip = true;
              textInfo.WritePrecedingWhiteSpace = false;
              isInline = true;
              break;
            case "a":
              if (node.Attributes.Contains("href")) {
                string href = node.Attributes["href"].Value.Trim();
                if (node.InnerText.IndexOf(href, StringComparison.InvariantCultureIgnoreCase) == -1) {
                  endElementString = "<" + href + ">";
                }
              }
              isInline = true;
              break;
            case "li":
              if (textInfo.ListIndex > 0) {
                outText.Write("\r\n{0}.\t", textInfo.ListIndex++);
              } else {
                outText.Write("\r\n*\t"); //using '*' as bullet char, with tab after, but whatever you want eg "\t->", if utf-8 0x2022
              }
              isInline = false;
              break;
            case "ol":
              listIndex = 1;
              goto case "ul";
            case "ul": //not handling nested lists any differently at this stage - that is getting close to rendering problems
              endElementString = "\r\n";
              isInline = false;
              break;
            case "img": //inline-block in reality
              if (node.Attributes.Contains("alt")) {
                outText.Write('[' + node.Attributes["alt"].Value);
                endElementString = "]";
              }
              if (node.Attributes.Contains("src")) {
                outText.Write('<' + node.Attributes["src"].Value + '>');
              }
              isInline = true;
              break;
            default:
              isInline = true;
              break;
          }
          if (!skip && node.HasChildNodes) {
            ConvertContentTo(node, outText, isInline ? textInfo : new PreceedingDomTextInfo(textInfo.IsFirstTextOfDocWritten) { ListIndex = listIndex });
          }
          if (endElementString != null) {
            outText.Write(endElementString);
          }
          break;
      }
    }
  }
  internal class PreceedingDomTextInfo {
    public PreceedingDomTextInfo(BoolWrapper isFirstTextOfDocWritten) {
      IsFirstTextOfDocWritten = isFirstTextOfDocWritten;
    }
    public bool WritePrecedingWhiteSpace { get; set; }
    public bool LastCharWasSpace { get; set; }
    public readonly BoolWrapper IsFirstTextOfDocWritten;
    public int ListIndex { get; set; }
  }
  internal class BoolWrapper {
    public BoolWrapper() { }
    public bool Value { get; set; }
    public static implicit operator bool(BoolWrapper boolWrapper) {
      return boolWrapper.Value;
    }
    public static implicit operator BoolWrapper(bool boolWrapper) {
      return new BoolWrapper { Value = boolWrapper };
    }
  }
}
sobelito
źródło
0

Myślę, że ma prostą odpowiedź:

public string RemoveHTMLTags(string HTMLCode)
{
    string str=System.Text.RegularExpressions.Regex.Replace(HTMLCode, "<[^>]*>", "");
    return str;
}
user3077654
źródło
0

Dla każdego, kto szuka dokładnego rozwiązania pytania OP dotyczącego skrótu tekstowego danego dokumentu html, bez znaków nowej linii i znaczników HTML, poniżej znajduje się rozwiązanie.

Podobnie jak w przypadku każdego proponowanego rozwiązania, z poniższym kodem są pewne założenia:

  • tagi script lub style nie powinny zawierać tagów script i style jako części skryptu
  • tylko główne elementy inline będą wstawiane bez spacji, tj. he<span>ll</span>opowinny być wyświetlane hello. Lista tagów wbudowanych: https://www.w3schools.com/htmL/html_blocks.asp

Biorąc pod uwagę powyższe, następujące rozszerzenie ciągu ze skompilowanymi wyrażeniami regularnymi wyświetli oczekiwany zwykły tekst w odniesieniu do znaków ze znakami ucieczki HTML i wartości null na wejściu o wartości null.

public static class StringExtensions
{
    public static string ConvertToPlain(this string html)
    {
        if (html == null)
        {
            return html;
        }

        html = scriptRegex.Replace(html, string.Empty);
        html = inlineTagRegex.Replace(html, string.Empty);
        html = tagRegex.Replace(html, " ");
        html = HttpUtility.HtmlDecode(html);
        html = multiWhitespaceRegex.Replace(html, " ");

        return html.Trim();
    }

    private static readonly Regex inlineTagRegex = new Regex("<\\/?(a|span|sub|sup|b|i|strong|small|big|em|label|q)[^>]*>", RegexOptions.Compiled | RegexOptions.Singleline);
    private static readonly Regex scriptRegex = new Regex("<(script|style)[^>]*?>.*?</\\1>", RegexOptions.Compiled | RegexOptions.Singleline);
    private static readonly Regex tagRegex = new Regex("<[^>]+>", RegexOptions.Compiled | RegexOptions.Singleline);
    private static readonly Regex multiWhitespaceRegex = new Regex("\\s+", RegexOptions.Compiled | RegexOptions.Singleline);
}
też
źródło
-4

public static string StripTags2 (string html) {return html.Replace ("<", "<"). Replace (">", ">"); }

W ten sposób usuwasz wszystkie „<” i „>” w ciągu. Czy to jest to, czego chcesz?

José Leal
źródło
... ach. Cóż, teraz odpowiedź (wraz z interpretacją niejednoznacznego pytania) całkowicie się zmieniła, wybiorę gnidy z braku & amp; zamiast kodowania. ;-)
bobince
2
Nie sądzę, aby wymyślanie na nowo koła było dobrym pomysłem - zwłaszcza gdy Twoje koło jest kwadratowe. Zamiast tego powinieneś użyć HTMLEncode.
Kramii