Como converter Html para texto simples?

Tenho excertos de Html armazenados numa tabela. Não páginas inteiras, sem etiquetas ou coisas do género, apenas formatação básica.

Eu gostaria de ser capaz de exibir esse Html apenas como texto, sem formatação, em uma dada página (na verdade, apenas os primeiros 30 - 50 caracteres, mas essa é a parte fácil).

Como faço para colocar o "texto" dentro desse Html em uma string como texto reto?

Então, este pedaço de código.

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

torna-se:

Olá, Mundo. Está aí alguém? lá fora?

Author: Michel Ayres, 2008-11-13

16 answers

Se está a falar de remoção de marcas, é relativamente simples se não tiver de se preocupar com coisas como as marcas <script>. Se tudo o que você precisa fazer é mostrar o texto sem as tags você pode realizar isso com uma expressão regular:

<[^>]*>

Se tiver de se preocupar com as marcas <script> e assim por diante, irá precisar de algo um pouco mais poderoso do que expressões regulares porque precisa de seguir o estado, omitindo algo mais como uma gramática sem contexto (CFG). Apesar de você pode ser capaz de realizá-lo com 'esquerda para a direita' ou combinação não-gananciosa.

Se você pode usar expressões regulares existem muitas páginas web por aí com boas informações:

Se precisar do comportamento mais complexo de um CFG, sugiro que use uma ferramenta de terceiros. boa recomendação.
 18
Author: vfilby, 2009-07-13 19:15:25

O código livre e aberto HtmlAgilityPack tem numa das suas amostras {[5] } um método que converte de HTML para texto simples.

var plainText = ConvertToPlainText(string html);

Dá-lhe um texto em HTML como

Olá, mundo!

E você terá um resultado de texto simples como:

hello world!
it is me!
 77
Author: Judah Himango, 2013-12-26 17:57:07

Eu não podia usar HtmlAgilityPack, então eu escrevi uma segunda melhor solução para mim

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;
}
 29
Author: Ben Anderson, 2013-05-06 21:06:12

HTTPUtility.HTMLEncode() destina-se a lidar com as marcas de HTML de codificação como strings. Trata de todo o trabalho pesado para ti. Da documentação MSDN:

Se caracteres como espaços em branco e pontuação são passados em um fluxo HTTP, eles podem ser mal interpretados no final de recepção. A codificação HTML converte caracteres que não são permitidos no HTML em equivalentes de entidade-carácter; a descodificação em HTML inverte a codificação. Por exemplo, quando embutido num bloco de texto, o os caracteres < e >, são codificados como &lt; e &gt; para transmissão HTTP.

HTTPUtility.HTMLEncode() método detalhado aqui:

public static void HtmlEncode(
  string s,
  TextWriter output
)

Utilização:

String TestString = "This is a <Test String>.";
StringWriter writer = new StringWriter();
Server.HtmlEncode(TestString, writer);
String EncodedString = writer.ToString();
 19
Author: George Stocker, 2015-06-09 15:19:22

Para adicionar à resposta do vfilby, pode apenas efectuar uma substituição RegEx dentro do seu código; não são necessárias novas classes. Para o caso de outros novatos como eu não se preocuparem com esta questão.

using System.Text.RegularExpressions;
Então...
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;
}
 10
Author: WEFX, 2011-03-11 18:14:03

Não existe um método com o nome 'ConvertToPlainText' no Pacote HtmlAgilityPack mas você pode converter um texto html para limpar o texto com:

HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(htmlString);
var textString = doc.DocumentNode.InnerText;
Regex.Replace(textString , @"<(.|n)*?>", string.Empty).Replace("&nbsp", "");
Por mim, tudo bem. Mas não encontro um método com o nome "ConvertToPlainText" em "HtmlAgilityPack".
 5
Author: Amine, 2013-04-26 13:58:24

Processo de três etapas para converter HTML em texto simples

Primeiro tem de instalar o pacote Nuget para HtmlAgilityPack Segunda criar esta classe

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;
        }
    }
}
Usando a classe acima com referência à resposta de Judah Himango.

Em terceiro lugar você precisa criar o objeto da classe acima e usar o Método ConvertHtml(HTMLContent) para converter HTML em texto simples em vez de ConvertToPlainText(string html);

HtmlToText htt=new HtmlToText();
var plainText = htt.ConvertHtml(HTMLContent);
 5
Author: Abdulqadir_WDDN, 2017-10-11 06:38:46

Ele tem uma limitação de que não colapsando espaço em branco, mas é definitivamente portátil e respeita layout como webbrowser.

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;
}
 4
Author: jeiea, 2018-05-16 05:37:50

Acho que a maneira mais fácil é fazer um método de extensão 'string' (baseado no que o utilizador Richard sugeriu):

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, "");
        }
}

Então use este método de extensão em qualquer variável 'string' do seu programa:

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

Eu uso este método de extensão para converter os comentários formatados html para texto simples para que ele seja exibido corretamente em um relatório de cristal, e ele funciona perfeitamente!

 3
Author: mik-t, 2012-05-08 21:52:34

A maneira mais simples que encontrei:

HtmlFilter.ConvertToPlainText(html);

A classe HtmlFilter está localizada na Microsoft.Descoberta em equipa.Procura de trabalho.Controlo.dll

O dll pode ser encontrado numa pasta como esta: %ProgramFiles%\Common Files\microsoft shared\Team Foundation Server\14.0\

Em VS 2015, o dll também requer referência à Microsoft.Descoberta em equipa.Procura de trabalho.Comum.dll, localizado na mesma pasta.

 3
Author: Roman O, 2017-04-19 12:48:36

Se tiver dados que tenham tags HTML e quiser mostrá-los para que uma pessoa possa ver as tags, use HttpServerUtility::HtmlEncode.

Se tiver dados que tenham marcas HTML nele e quiser que o utilizador veja as marcas renderizadas, então mostre o texto tal como está. Se o texto representa uma página web inteira, use um IFRAME para ele.

Se tiver dados que tenham marcas de HTML e quiser remover as marcas e apenas mostrar o texto não formatado, use uma expressão regular.

 2
Author: Corey Trager, 2008-11-13 12:41:31

Depende do que quer dizer com "html."O caso mais complexo seria páginas web completas. Isso também é o mais fácil de lidar, uma vez que você pode usar um navegador de modo de texto web. Veja o artigo do Wikipédia a listar navegadores web, incluindo navegadores de modo de texto. Lynx é provavelmente o mais conhecido, mas um dos outros pode ser melhor para as suas necessidades.

 0
Author: mpez0, 2008-11-13 12:46:54
Aqui está a minha solução:
public string StripHTML(string html)
{
    var regex = new Regex("<[^>]+>", RegexOptions.IgnoreCase);
    return System.Web.HttpUtility.HtmlDecode((regex.Replace(html, "")));
}

Exemplo:

StripHTML("<p class='test' style='color:red;'>Here is my solution:</p>");
// output -> Here is my solution:
 0
Author: Mehdi Dehghani, 2017-11-03 09:25:30

Eu tinha a mesma pergunta, só que o meu html tinha um layout simples Pré-conhecido, como:

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

Então acabei por usar um código tão simples:

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

Que Saídas:

abc
def
 0
Author: Karlas, 2018-04-17 13:45:41

Não escrevia, mas utilizava:

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 };
    }
  }
}
 0
Author: sobelito, 2018-04-29 10:16:07

StripTags2 estático público (string html) { devolve html.Substituir("", ">"); }

Por isso você escapa de tudo " " em uma corda. É isto que queres?

 -4
Author: José Leal, 2008-11-13 12:44:18