¿Cómo se convierte HTML a texto sin formato?


98

Tengo fragmentos de Html almacenados en una tabla. No páginas enteras, etiquetas o similares, solo formato básico.

Me gustaría poder mostrar ese Html solo como texto, sin formato , en una página determinada (en realidad, solo los primeros 30 a 50 caracteres, pero eso es lo fácil).

¿Cómo coloco el "texto" dentro de ese Html en una cadena como texto simple?

Entonces este fragmento de código.

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

Se convierte en:

Hola Mundo. ¿Hay alguien ahí afuera?


Es posible que desee utilizar SgmlReader. code.msdn.microsoft.com/SgmlReader
Leonardo Herrera

Hay un código bastante simple y directo para convertir HTML a texto sin formato en blackbeltcoder.com/Articles/strings/convert-html-to-text .
Jonathan Wood

Esta fue la respuesta correcta para lo que necesitaba, ¡gracias!
Shaul Behr

Hay algunas buenas sugerencias del W3C aquí: w3.org/Tools/html2things.html
Rich

4
¿Cómo se puede marcar una pregunta como duplicado de una pregunta que se hizo 6 meses después? Parece un poco atrasado ...
Stuart Helwig

Respuestas:


27

Si está hablando de la eliminación de etiquetas, es relativamente sencillo si no tiene que preocuparse por cosas como las <script>etiquetas. Si todo lo que necesita hacer es mostrar el texto sin las etiquetas, puede hacerlo con una expresión regular:

<[^>]*>

Si tiene que preocuparse por las <script>etiquetas y cosas por el estilo, entonces necesitará algo un poco más poderoso que las expresiones regulares porque necesita rastrear el estado, algo más como una gramática libre de contexto (CFG). Aunque es posible que pueda lograrlo con "De izquierda a derecha" o con coincidencias no codiciosas.

Si puede usar expresiones regulares, hay muchas páginas web con buena información:

Si necesita el comportamiento más complejo de un CFG, sugeriría usar una herramienta de terceros, desafortunadamente no conozco una buena para recomendar.


3
También tiene que preocuparse por> valores de atributos, comentarios, PI / CDATA en XML y varios errores de formato comunes en HTML heredado. En general, [X] [HT] ML no se puede analizar con expresiones regulares.
Bobince

11
Este es un método terrible para hacerlo. La forma correcta es analizar el HTML con una lib y recorrer el dom generando solo contenido de la lista blanca.
usr

2
@usr: La parte a la que te refieres es la parte CFG de la respuesta. Regex se puede usar para quitar etiquetas rápidas y sucias, tiene sus debilidades pero es rápido y fácil. Para un análisis más complicado, use una herramienta basada en CFG (en su lenguaje, una biblioteca que genera un DOM). No he realizado las pruebas, pero apuesto a que el análisis de DOM es más lento que la eliminación de expresiones regulares, en caso de que se deba considerar el rendimiento.
vfilby

1
@vfilby, el primer ataque que me viene a la mente es escribir "<div id = \" "(sintaxis de cadena c #). Observe las comillas finales que faltan y la llave de cierre. Supongo que esto confundirá al navegador y desequilibrará la estructura de la etiqueta. ¿Piensas en este ataque? ¿Puedes estar seguro de que nunca funciona? Desagradable.
usr

1
@vfilby, no importa si la biblioteca de análisis se confunde o no. Todo lo que necesita hacer es quitarle el DOM (cualquier DOM) y generar solo los componentes de la lista blanca. Esto siempre es seguro, no importa cómo se vea el DOM analizado. Además, te conté varios ejemplos en los que tu método "simple" no eliminará las etiquetas.
usr

95

El HtmlAgilityPack gratuito y de código abierto tiene en una de sus muestras un método que convierte de HTML a texto sin formato.

var plainText = HtmlUtilities.ConvertToPlainText(string html);

Aliméntelo con una cadena HTML como

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

Y obtendrás un resultado de texto sin formato como:

hello world!

10
He usado HtmlAgilityPack antes pero no puedo ver ninguna referencia a ConvertToPlainText. ¿Puedes decirme dónde puedo encontrarlo?
horacio

8
Horatio, se incluye en una de las muestras que viene con HtmlAgilityPack: htmlagilitypack.codeplex.com/sourcecontrol/changeset/view/…
Judah Gabriel Himango

5
En realidad, no hay un método integrado para esto en el Agility Pack. Lo que se ha vinculado a un ejemplo que utiliza el paquete de agilidad para atravesar el nodo del árbol, retire scripty styleetiquetas y escribir el texto interno de otros elementos en la cadena de salida. Dudo que haya pasado muchas pruebas con entradas del mundo real.
Lou

3
¿Alguien puede proporcionar un código que funcione, en lugar de enlaces a muestras que deben adaptarse para que funcionen correctamente?
Eric K

5
La muestra ahora se puede encontrar aquí: github.com/ceee/ReadSharp/blob/master/ReadSharp/…
StuartQ

51

No pude usar HtmlAgilityPack, así que escribí una segunda mejor solución para mí

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

2
& lt; blabla & gt; fue analizado, así que moví el texto = System.Net.WebUtility.HtmlDecode (text); al final del método
Luuk

1
Esto fue genial, también agregué un condensador multiespacio ya que el html podría haber sido generado desde un CMS: var spaceRegex = new Regex ("[] {2,}", RegexOptions.None);
Enkode

En algún momento, en el código html hay una nueva línea del codificador (la nueva línea no se puede ver en el comentario, así que la muestro con [nueva línea], como: <br> [nueva línea] extraño [nueva línea] usted <br >, Así que se supone que muestra: "Te extraño", pero muestra que [nueva línea] extraño [nueva línea] te. Esto hace que el texto sin formato parezca doloroso. ¿Sabes cómo solucionarlo?
123iamking

@ 123iamking puedes usar esto antes de devolver el texto; : text.Replace ("[nueva línea]", "\ n");
Eslam Badawy

Estaba usando esto y me di cuenta de que a veces deja '>' al comienzo de las cadenas. La otra solución de aplicar regex <[^>] *> funciona bien.
Etienne Charland

20

HTTPUtility.HTMLEncode()está destinado a manejar la codificación de etiquetas HTML como cadenas. Se encarga de todo el trabajo pesado por ti. De la documentación de MSDN :

Si se pasan caracteres como espacios en blanco y puntuación en una secuencia HTTP, es posible que se malinterpreten en el extremo receptor. La codificación HTML convierte caracteres que no están permitidos en HTML en equivalentes de entidad de carácter; La decodificación HTML invierte la codificación. Por ejemplo, cuando se incrusta en un bloque de texto, los caracteres <y >, se codifican como &lt;y &gt;para la transmisión HTTP.

HTTPUtility.HTMLEncode()método, detallado aquí :

public static void HtmlEncode(
  string s,
  TextWriter output
)

Uso:

String TestString = "This is a <Test String>.";
StringWriter writer = new StringWriter();
Server.HtmlEncode(TestString, writer);
String EncodedString = writer.ToString();

Una muy buena respuesta, gracias George, también destacó lo mal que hice la pregunta la primera vez. Lo siento.
Stuart Helwig

El paquete de agilidad html está desactualizado y no es compatible con html5
abzarak

10

Para agregar a la respuesta de vfilby, puede simplemente realizar un reemplazo de RegEx dentro de su código; no son necesarias nuevas clases. En caso de que otros novatos como yo se metan con esta pregunta.

using System.Text.RegularExpressions;

Luego...

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

19
¡NO ESTÁ BIEN! Esto se puede engañar para que contenga el guión omitiendo el corchete angular de cierre. CHICOS, nunca hagan listas negras. No puede desinfectar la entrada mediante la lista negra. Esto esta muy mal.
usr

7

Proceso de tres pasos para convertir HTML en texto sin formato

Primero debe instalar el paquete Nuget para HtmlAgilityPack En segundo lugar, cree esta clase

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

Al usar la clase anterior con referencia a la respuesta de Judah Himango

En tercer lugar, debe crear el objeto de la clase anterior y usar el ConvertHtml(HTMLContent)método para convertir HTML en texto sin formato en lugar deConvertToPlainText(string html);

HtmlToText htt=new HtmlToText();
var plainText = htt.ConvertHtml(HTMLContent);

¿Puedo omitir la conversión de enlaces en html? ¿Necesito mantener los enlaces en html al convertir a texto?
coder771

6

Tiene la limitación de no colapsar espacios en blanco largos en línea, pero definitivamente es portátil y respeta el diseño como el navegador web.

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

No existe un método con el nombre 'ConvertToPlainText' en el HtmlAgilityPack, pero puede convertir una cadena html en una cadena CLEAR con:

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

Eso funciona para mí. PERO NO ENCUENTRO UN MÉTODO CON EL NOMBRE 'ConvertToPlainText' EN 'HtmlAgilityPack'.


3

Creo que la forma más fácil es hacer un método de extensión de 'cadena' (basado en lo que sugirió el usuario Richard):

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

Luego, use este método de extensión en cualquier variable de 'cadena' en su programa:

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

Utilizo este método de extensión para convertir comentarios formateados html a texto sin formato para que se muestre correctamente en un informe de Crystal, ¡y funciona perfectamente!


3

La forma más sencilla que encontré:

HtmlFilter.ConvertToPlainText(html);

La clase HtmlFilter se encuentra en Microsoft.TeamFoundation.WorkItemTracking.Controls.dll

El dll se puede encontrar en una carpeta como esta:% ProgramFiles% \ Common Files \ microsoft shared \ Team Foundation Server \ 14.0 \

En VS 2015, el dll también requiere una referencia a Microsoft.TeamFoundation.WorkItemTracking.Common.dll, ubicado en la misma carpeta.


¿Se ocupa de las etiquetas de script y se formatea como negrita, cursiva, etc.?
Samra

Presentamos una dependencia de base de equipo para convertir HTML a texto sin formato, muy cuestionable ...
ViRuSTriNiDAD

2

Si tiene datos que tienen etiquetas HTML y desea mostrarlos para que una persona pueda VER las etiquetas, use HttpServerUtility :: HtmlEncode.

Si tiene datos que contienen etiquetas HTML y desea que el usuario vea las etiquetas representadas, muestre el texto tal cual. Si el texto representa una página web completa, use un IFRAME para ello.

Si tiene datos que tienen etiquetas HTML y desea eliminar las etiquetas y simplemente mostrar el texto sin formato, use una expresión regular.


en php hay una función llamada striptags () tal vez tenga algo similar
markus

"usa una expresión regular" ¡NO! Esto sería una lista negra. Solo puede estar seguro haciendo listas blancas. Por ejemplo, ¿habría recordado que el atributo de estilo puede contener "background: url ('javascript: ...');"? por supuesto que no, yo tampoco lo habría hecho. Es por eso que las listas negras no funcionan.
usr

2

Me he enfrentado a un problema similar y he encontrado la mejor solución. El siguiente código funciona perfecto para mí.

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

}

Los caracteres de escape como \ n y \ r tuvieron que eliminarse primero porque hacen que las expresiones regulares dejen de funcionar como se esperaba.

Además, para que la cadena de resultado se muestre correctamente en el cuadro de texto, es posible que deba dividirla y establecer la propiedad Lines del cuadro de texto en lugar de asignarla a la propiedad Text.

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

Fuente: https://www.codeproject.com/Articles/11902/Convert-HTML-to-Plain-Text-2


0

Depende de lo que quieras decir con "html". El caso más complejo serían las páginas web completas. También es el más fácil de manejar, ya que puede usar un navegador web en modo texto. Consulte el artículo de Wikipedia que enumera los navegadores web, incluidos los navegadores en modo texto. Lynx es probablemente el más conocido, pero uno de los otros puede ser mejor para sus necesidades.


como dijo "Tengo fragmentos de Html almacenados en una tabla".
M el

0

Aquí está mi solución:

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

Ejemplo:

StripHTML("<p class='test' style='color:red;'>Here is my solution:</p>");
// output -> Here is my solution:

0

Tenía la misma pregunta, solo que mi html tenía un diseño simple conocido, como:

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

Así que terminé usando un código tan simple:

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

Qué salidas:

abc
def

0

No escribí, pero usé:

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

Creo que tiene una respuesta simple:

public string RemoveHTMLTags(string HTMLCode)
{
    string str=System.Text.RegularExpressions.Regex.Replace(HTMLCode, "<[^>]*>", "");
    return str;
}

0

Para cualquiera que busque una solución exacta a la pregunta OP para una abreviatura textual de un documento html dado, sin nuevas líneas ni etiquetas HTML, encuentre la solución a continuación.

Al igual que con cada solución propuesta, hay algunas suposiciones con el siguiente código:

  • Las etiquetas de estilo o script no deben contener etiquetas de estilo o script como parte del script.
  • solo los elementos en línea principales se insertarán sin espacio, es decir, he<span>ll</span>odeberían aparecer hello. Lista de etiquetas en línea: https://www.w3schools.com/htmL/html_blocks.asp

Teniendo en cuenta lo anterior, la siguiente extensión de cadena con expresiones regulares compiladas generará el texto sin formato esperado con respecto a los caracteres de escape html y nulo en la entrada nula.

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

-4

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

De esta forma, se escapan todos los "<" y ">" en una cadena. ¿Es esto lo que quieres?


... ah. Bueno, ahora la respuesta (junto con la interpretación de la pregunta ambigua) ha cambiado por completo, recogeré liendres por la falta de & amp; codificación en su lugar. ;-)
bobince

2
No creo que sea una buena idea reinventar la rueda, especialmente cuando la rueda es cuadrada. En su lugar, debería utilizar HTMLEncode.
Kramii
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.