天天看点

HTML 转文本及HTML内容提取(C#)

[csharp] view plaincopy

  1. //1、HTML直接转文本  
  2. //使用方法  
  3. HtmlToText convert = new HtmlToText();  
  4. textBox2.Text = convert.Convert(textBox1.Text);  
  5. //代码  
  6. /// <summary>  
  7. /// Converts HTML to plain text.  
  8. /// </summary>  
  9. class HtmlToText  
  10. {  
  11.     // Static data tables  
  12.     protected static Dictionary<string, string> _tags;  
  13.     protected static HashSet<string> _ignoreTags;  
  14.     // Instance variables  
  15.     protected TextBuilder _text;  
  16.     protected string _html;  
  17.     protected int _pos;  
  18.     // Static constructor (one time only)  
  19.     static HtmlToText()  
  20.     {  
  21.         _tags = new Dictionary<string, string>();  
  22.         _tags.Add("address", "\n");  
  23.         _tags.Add("blockquote", "\n");  
  24.         _tags.Add("div", "\n");  
  25.         _tags.Add("dl", "\n");  
  26.         _tags.Add("fieldset", "\n");  
  27.         _tags.Add("form", "\n");  
  28.         _tags.Add("h1", "\n");  
  29.         _tags.Add("/h1", "\n");  
  30.         _tags.Add("h2", "\n");  
  31.         _tags.Add("/h2", "\n");  
  32.         _tags.Add("h3", "\n");  
  33.         _tags.Add("/h3", "\n");  
  34.         _tags.Add("h4", "\n");  
  35.         _tags.Add("/h4", "\n");  
  36.         _tags.Add("h5", "\n");  
  37.         _tags.Add("/h5", "\n");  
  38.         _tags.Add("h6", "\n");  
  39.         _tags.Add("/h6", "\n");  
  40.         _tags.Add("p", "\n");  
  41.         _tags.Add("/p", "\n");  
  42.         _tags.Add("table", "\n");  
  43.         _tags.Add("/table", "\n");  
  44.         _tags.Add("ul", "\n");  
  45.         _tags.Add("/ul", "\n");  
  46.         _tags.Add("ol", "\n");  
  47.         _tags.Add("/ol", "\n");  
  48.         _tags.Add("/li", "\n");  
  49.         _tags.Add("br", "\n");  
  50.         _tags.Add("/td", "\t");  
  51.         _tags.Add("/tr", "\n");  
  52.         _tags.Add("/pre", "\n");  
  53.         _ignoreTags = new HashSet<string>();  
  54.         _ignoreTags.Add("script");  
  55.         _ignoreTags.Add("noscript");  
  56.         _ignoreTags.Add("style");  
  57.         _ignoreTags.Add("object");  
  58.     }  
  59.     /// <summary>  
  60.     /// Converts the given HTML to plain text and returns the result.  
  61.     /// </summary>  
  62.     /// <param name="html">HTML to be converted</param>  
  63.     /// <returns>Resulting plain text</returns>  
  64.     public string Convert(string html)  
  65.         // Initialize state variables  
  66.         _text = new TextBuilder();  
  67.         _html = html;  
  68.         _pos = 0;  
  69.         // Process input  
  70.         while (!EndOfText)  
  71.         {  
  72.             if (Peek() == '<')  
  73.             {  
  74.                 // HTML tag  
  75.                 bool selfClosing;  
  76.                 string tag = ParseTag(out selfClosing);  
  77.                 // Handle special tag cases  
  78.                 if (tag == "body")  
  79.                 {  
  80.                     // Discard content before <body>  
  81.                     _text.Clear();  
  82.                 }  
  83.                 else if (tag == "/body")  
  84.                     // Discard content after </body>  
  85.                     _pos = _html.Length;  
  86.                 else if (tag == "pre")  
  87.                     // Enter preformatted mode  
  88.                     _text.Preformatted = true;  
  89.                     EatWhitespaceToNextLine();  
  90.                 else if (tag == "/pre")  
  91.                     // Exit preformatted mode  
  92.                     _text.Preformatted = false;  
  93.                 string value;  
  94.                 if (_tags.TryGetValue(tag, out value))  
  95.                     _text.Write(value);  
  96.                 if (_ignoreTags.Contains(tag))  
  97.                     EatInnerContent(tag);  
  98.             }  
  99.             else if (Char.IsWhiteSpace(Peek()))  
  100.                 // Whitespace (treat all as space)  
  101.                 _text.Write(_text.Preformatted ? Peek() : ' ');  
  102.                 MoveAhead();  
  103.             else  
  104.                 // Other text  
  105.                 _text.Write(Peek());  
  106.         }  
  107.         // Return result  
  108.         return HttpUtility.HtmlDecode(_text.ToString());  
  109.     // Eats all characters that are part of the current tag  
  110.     // and returns information about that tag  
  111.     protected string ParseTag(out bool selfClosing)  
  112.         string tag = String.Empty;  
  113.         selfClosing = false;  
  114.         if (Peek() == '<')  
  115.             MoveAhead();  
  116.             // Parse tag name  
  117.             EatWhitespace();  
  118.             int start = _pos;  
  119.             if (Peek() == '/')  
  120.             while (!EndOfText && !Char.IsWhiteSpace(Peek()) &&  
  121.                 Peek() != '/' && Peek() != '>')  
  122.             tag = _html.Substring(start, _pos - start).ToLower();  
  123.             // Parse rest of tag  
  124.             while (!EndOfText && Peek() != '>')  
  125.                 if (Peek() == '"' || Peek() == '\'')  
  126.                     EatQuotedValue();  
  127.                 else  
  128.                     if (Peek() == '/')  
  129.                         selfClosing = true;  
  130.                     MoveAhead();  
  131.         return tag;  
  132.     // Consumes inner content from the current tag  
  133.     protected void EatInnerContent(string tag)  
  134.         string endTag = "/" + tag;  
  135.                 // Consume a tag  
  136.                 if (ParseTag(out selfClosing) == endTag)  
  137.                     return;  
  138.                 // Use recursion to consume nested tags  
  139.                 if (!selfClosing && !tag.StartsWith("/"))  
  140.             else MoveAhead();  
  141.     // Returns true if the current position is at the end of  
  142.     // the string  
  143.     protected bool EndOfText  
  144.         get { return (_pos >= _html.Length); }  
  145.     // Safely returns the character at the current position  
  146.     protected char Peek()  
  147.         return (_pos < _html.Length) ? _html[_pos] : (char)0;  
  148.     // Safely advances to current position to the next character  
  149.     protected void MoveAhead()  
  150.         _pos = Math.Min(_pos + 1, _html.Length);  
  151.     // Moves the current position to the next non-whitespace  
  152.     // character.  
  153.     protected void EatWhitespace()  
  154.         while (Char.IsWhiteSpace(Peek()))  
  155.     // character or the start of the next line, whichever  
  156.     // comes first  
  157.     protected void EatWhitespaceToNextLine()  
  158.             char c = Peek();  
  159.             if (c == '\n')  
  160.                 break;  
  161.     // Moves the current position past a quoted value  
  162.     protected void EatQuotedValue()  
  163.         char c = Peek();  
  164.         if (c == '"' || c == '\'')  
  165.             // Opening quote  
  166.             // Find end of value  
  167.             _pos = _html.IndexOfAny(new char[] { c, '\r', '\n' }, _pos);  
  168.             if (_pos < 0)  
  169.                 _pos = _html.Length;  
  170.                 MoveAhead();    // Closing quote  
  171.     /// A StringBuilder class that helps eliminate excess whitespace.  
  172.     protected class TextBuilder  
  173.         private StringBuilder _text;  
  174.         private StringBuilder _currLine;  
  175.         private int _emptyLines;  
  176.         private bool _preformatted;  
  177.         // Construction  
  178.         public TextBuilder()  
  179.             _text = new StringBuilder();  
  180.             _currLine = new StringBuilder();  
  181.             _emptyLines = 0;  
  182.             _preformatted = false;  
  183.         /// <summary>  
  184.         /// Normally, extra whitespace characters are discarded.  
  185.         /// If this property is set to true, they are passed  
  186.         /// through unchanged.  
  187.         /// </summary>  
  188.         public bool Preformatted  
  189.             get  
  190.                 return _preformatted;  
  191.             set  
  192.                 if (value)  
  193.                     // Clear line buffer if changing to  
  194.                     // preformatted mode  
  195.                     if (_currLine.Length > 0)  
  196.                         FlushCurrLine();  
  197.                     _emptyLines = 0;  
  198.                 _preformatted = value;  
  199.         /// Clears all current text.  
  200.         public void Clear()  
  201.             _text.Length = 0;  
  202.             _currLine.Length = 0;  
  203.         /// Writes the given string to the output buffer.  
  204.         /// <param name="s"></param>  
  205.         public void Write(string s)  
  206.             foreach (char c in s)  
  207.                 Write(c);  
  208.         /// Writes the given character to the output buffer.  
  209.         /// <param name="c">Character to write</param>  
  210.         public void Write(char c)  
  211.             if (_preformatted)  
  212.                 // Write preformatted character  
  213.                 _text.Append(c);  
  214.                 if (c == '\r')  
  215.                     // Ignore carriage returns. We'll process  
  216.                     // '\n' if it comes next  
  217.                 else if (c == '\n')  
  218.                     // Flush current line  
  219.                     FlushCurrLine();  
  220.                 else if (Char.IsWhiteSpace(c))  
  221.                     // Write single space character  
  222.                     int len = _currLine.Length;  
  223.                     if (len == 0 || !Char.IsWhiteSpace(_currLine[len - 1]))  
  224.                         _currLine.Append(' ');  
  225.                     // Add character to current line  
  226.                     _currLine.Append(c);  
  227.         // Appends the current line to output buffer  
  228.         protected void FlushCurrLine()  
  229.             // Get current line  
  230.             string line = _currLine.ToString().Trim();  
  231.             // Determine if line contains non-space characters  
  232.             string tmp = line.Replace(" ", String.Empty);  
  233.             if (tmp.Length == 0)  
  234.                 // An empty line  
  235.                 _emptyLines++;  
  236.                 if (_emptyLines < 2 && _text.Length > 0)  
  237.                     _text.AppendLine(line);  
  238.                 // A non-empty line  
  239.                 _emptyLines = 0;  
  240.                 _text.AppendLine(line);  
  241.             // Reset current line  
  242.         /// Returns the current output as a string.  
  243.         public override string ToString()  
  244.             if (_currLine.Length > 0)  
  245.                 FlushCurrLine();  
  246.             return _text.ToString();  
  247. }  
  248. //2、提取html的正文 类  
  249. using System;  
  250.  using System.Text;  
  251.  namespace HtmlStrip  
  252.  {  
  253.      class MainClass  
  254.      {  
  255.          public static void Main (string[] args)  
  256.          {  
  257.              string str = "<div>abc</div><span>efg</span><br /><script>888</script><!--<PA>WW</PA-->oo";  
  258.              //System.IO.StreamReader rd=new System.IO.StreamReader ("/home/lx/test.html");  
  259.              //str=rd.ReadToEnd ();  
  260.              HtmlParser t = new HtmlParser (str); //  
  261.              t.KeepTag (new string[] { "br" }); //设置br标签不过虑  
  262.              Console.Write (t.Text ());  
  263.          }  
  264.      }  
  265.      class HtmlParser  
  266.          private string[] htmlcode; //把html转为数组形式用于分析  
  267.          private StringBuilder result = new StringBuilder ();  //输出的结果  
  268.          private int seek; //分析文本时候的指针位置  
  269.          private string[] keepTag;  //用于保存要保留的尖括号内容  
  270.          private bool _inTag;  //标记现在的指针是不是在尖括号内  
  271.          private bool needContent = true;  //是否要提取正文  
  272.          private string tagName;  //当前尖括号的名字  
  273.          private string[] specialTag = new string[] { "script", "style", "!--" };  //特殊的尖括号内容,一般这些标签的正文是不要的  
  274.          /// <summary>  
  275.          /// 当指针进入尖括号内,就会触发这个属性。这里主要逻辑是提取尖括号里的标签名字  
  276.          /// </summary>  
  277.          public bool inTag {  
  278.              get { return _inTag; }  
  279.              set {  
  280.                  _inTag = value;  
  281.                  if (!value)  
  282.                      return;  
  283.                  bool ok = true;  
  284.                  tagName = "";  
  285.                  while (ok) {  
  286.                      string word = read ();  
  287.                      if (word != " " && word != ">") {  
  288.                          tagName += word;  
  289.                      } else if (word == " " && tagName.Length > 0) {  
  290.                          ok = false;  
  291.                      } else if (word == ">") {  
  292.                          inTag = false;  
  293.                          seek -= 1;  
  294.                      }  
  295.                  }  
  296.              }  
  297.          /// 初始化类  
  298.          /// <param name="html">  
  299.          ///  要分析的html代码  
  300.          /// </param>  
  301.          public HtmlParser (string html)  
  302.              htmlcode = new string[html.Length];  
  303.              for (int i = 0; i < html.Length; i++) {  
  304.                  htmlcode[i] = html[i].ToString ();  
  305.              KeepTag (new string[] {  });  
  306.          /// 设置要保存那些标签不要被过滤掉  
  307.          /// <param name="tags">  
  308.          ///  
  309.          public void KeepTag (string[] tags)  
  310.              keepTag = tags;  
  311.          ///   
  312.          /// <returns>  
  313.          /// 输出处理后的文本  
  314.          /// </returns>  
  315.          public string Text ()  
  316.              int startTag = 0;  
  317.              int endTag = 0;  
  318.              while (seek < htmlcode.Length) {  
  319.                  string word = read ();  
  320.                  if (word.ToLower () == "<") {  
  321.                      startTag = seek;  
  322.                      inTag = true;  
  323.                  } else if (word.ToLower () == ">") {  
  324.                      endTag = seek;  
  325.                      inTag = false;  
  326.                      if (iskeepTag (tagName.Replace ("/", ""))) {  
  327.                          for (int i = startTag - 1; i < endTag; i++) {  
  328.                              result.Append (htmlcode[i].ToString ());  
  329.                          }  
  330.                      } else if (tagName.StartsWith ("!--")) {  
  331.                          bool ok = true;  
  332.                          while (ok) {  
  333.                              if (read () == "-") {  
  334.                                  if (read () == "-") {  
  335.                                      if (read () == ">") {  
  336.                                          ok = false;  
  337.                                      } else {  
  338.                                          seek -= 1;  
  339.                                      }  
  340.                                  }  
  341.                              }  
  342.                      } else {  
  343.                          foreach (string str in specialTag) {  
  344.                              if (tagName == str) {  
  345.                                  needContent = false;  
  346.                                  break;  
  347.                              } else  
  348.                                  needContent = true;  
  349.                  } else if (!inTag && needContent) {  
  350.                      result.Append (word);  
  351.              return result.ToString ();  
  352.          /// 判断是否要保存这个标签  
  353.          /// <param name="tag">  
  354.          /// A <see cref="System.String"/>  
  355.          /// A <see cref="System.Boolean"/>  
  356.          private bool iskeepTag (string tag)  
  357.              foreach (string ta in keepTag) {  
  358.                  if (tag.ToLower () == ta.ToLower ()) {  
  359.                      return true;  
  360.              return false;  
  361.          private string read ()  
  362.              return htmlcode[seek++];  
  363.  }  

引文原址:http://blog.csdn.net/cjh200102/article/details/6824895