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

[csharp] view plaincopy
 
  1. //1、HTML直接转文本  
  2.   
  3. //使用方法  
  4. HtmlToText convert = new HtmlToText();  
  5. textBox2.Text = convert.Convert(textBox1.Text);  
  6.   
  7.   
  8. //代码  
  9. /// <summary>  
  10. /// Converts HTML to plain text.  
  11. /// </summary>  
  12. class HtmlToText  
  13. {  
  14.     // Static data tables  
  15.     protected static Dictionary<stringstring> _tags;  
  16.     protected static HashSet<string> _ignoreTags;  
  17.   
  18.     // Instance variables  
  19.     protected TextBuilder _text;  
  20.     protected string _html;  
  21.     protected int _pos;  
  22.   
  23.     // Static constructor (one time only)  
  24.     static HtmlToText()  
  25.     {  
  26.         _tags = new Dictionary<stringstring>();  
  27.         _tags.Add("address""\n");  
  28.         _tags.Add("blockquote""\n");  
  29.         _tags.Add("div""\n");  
  30.         _tags.Add("dl""\n");  
  31.         _tags.Add("fieldset""\n");  
  32.         _tags.Add("form""\n");  
  33.         _tags.Add("h1""\n");  
  34.         _tags.Add("/h1""\n");  
  35.         _tags.Add("h2""\n");  
  36.         _tags.Add("/h2""\n");  
  37.         _tags.Add("h3""\n");  
  38.         _tags.Add("/h3""\n");  
  39.         _tags.Add("h4""\n");  
  40.         _tags.Add("/h4""\n");  
  41.         _tags.Add("h5""\n");  
  42.         _tags.Add("/h5""\n");  
  43.         _tags.Add("h6""\n");  
  44.         _tags.Add("/h6""\n");  
  45.         _tags.Add("p""\n");  
  46.         _tags.Add("/p""\n");  
  47.         _tags.Add("table""\n");  
  48.         _tags.Add("/table""\n");  
  49.         _tags.Add("ul""\n");  
  50.         _tags.Add("/ul""\n");  
  51.         _tags.Add("ol""\n");  
  52.         _tags.Add("/ol""\n");  
  53.         _tags.Add("/li""\n");  
  54.         _tags.Add("br""\n");  
  55.         _tags.Add("/td""\t");  
  56.         _tags.Add("/tr""\n");  
  57.         _tags.Add("/pre""\n");  
  58.   
  59.         _ignoreTags = new HashSet<string>();  
  60.         _ignoreTags.Add("script");  
  61.         _ignoreTags.Add("noscript");  
  62.         _ignoreTags.Add("style");  
  63.         _ignoreTags.Add("object");  
  64.     }  
  65.   
  66.     /// <summary>  
  67.     /// Converts the given HTML to plain text and returns the result.  
  68.     /// </summary>  
  69.     /// <param name="html">HTML to be converted</param>  
  70.     /// <returns>Resulting plain text</returns>  
  71.     public string Convert(string html)  
  72.     {  
  73.         // Initialize state variables  
  74.         _text = new TextBuilder();  
  75.         _html = html;  
  76.         _pos = 0;  
  77.   
  78.         // Process input  
  79.         while (!EndOfText)  
  80.         {  
  81.             if (Peek() == '<')  
  82.             {  
  83.                 // HTML tag  
  84.                 bool selfClosing;  
  85.                 string tag = ParseTag(out selfClosing);  
  86.   
  87.                 // Handle special tag cases  
  88.                 if (tag == "body")  
  89.                 {  
  90.                     // Discard content before <body>  
  91.                     _text.Clear();  
  92.                 }  
  93.                 else if (tag == "/body")  
  94.                 {  
  95.                     // Discard content after </body>  
  96.                     _pos = _html.Length;  
  97.                 }  
  98.                 else if (tag == "pre")  
  99.                 {  
  100.                     // Enter preformatted mode  
  101.                     _text.Preformatted = true;  
  102.                     EatWhitespaceToNextLine();  
  103.                 }  
  104.                 else if (tag == "/pre")  
  105.                 {  
  106.                     // Exit preformatted mode  
  107.                     _text.Preformatted = false;  
  108.                 }  
  109.   
  110.                 string value;  
  111.                 if (_tags.TryGetValue(tag, out value))  
  112.                     _text.Write(value);  
  113.   
  114.                 if (_ignoreTags.Contains(tag))  
  115.                     EatInnerContent(tag);  
  116.             }  
  117.             else if (Char.IsWhiteSpace(Peek()))  
  118.             {  
  119.                 // Whitespace (treat all as space)  
  120.                 _text.Write(_text.Preformatted ? Peek() : ' ');  
  121.                 MoveAhead();  
  122.             }  
  123.             else  
  124.             {  
  125.                 // Other text  
  126.                 _text.Write(Peek());  
  127.                 MoveAhead();  
  128.             }  
  129.         }  
  130.         // Return result  
  131.         return HttpUtility.HtmlDecode(_text.ToString());  
  132.     }  
  133.   
  134.     // Eats all characters that are part of the current tag  
  135.     // and returns information about that tag  
  136.     protected string ParseTag(out bool selfClosing)  
  137.     {  
  138.         string tag = String.Empty;  
  139.         selfClosing = false;  
  140.   
  141.         if (Peek() == '<')  
  142.         {  
  143.             MoveAhead();  
  144.   
  145.             // Parse tag name  
  146.             EatWhitespace();  
  147.             int start = _pos;  
  148.             if (Peek() == '/')  
  149.                 MoveAhead();  
  150.             while (!EndOfText && !Char.IsWhiteSpace(Peek()) &&  
  151.                 Peek() != '/' && Peek() != '>')  
  152.                 MoveAhead();  
  153.             tag = _html.Substring(start, _pos - start).ToLower();  
  154.   
  155.             // Parse rest of tag  
  156.             while (!EndOfText && Peek() != '>')  
  157.             {  
  158.                 if (Peek() == '"' || Peek() == '\'')  
  159.                     EatQuotedValue();  
  160.                 else  
  161.                 {  
  162.                     if (Peek() == '/')  
  163.                         selfClosing = true;  
  164.                     MoveAhead();  
  165.                 }  
  166.             }  
  167.             MoveAhead();  
  168.         }  
  169.         return tag;  
  170.     }  
  171.   
  172.     // Consumes inner content from the current tag  
  173.     protected void EatInnerContent(string tag)  
  174.     {  
  175.         string endTag = "/" + tag;  
  176.   
  177.         while (!EndOfText)  
  178.         {  
  179.             if (Peek() == '<')  
  180.             {  
  181.                 // Consume a tag  
  182.                 bool selfClosing;  
  183.                 if (ParseTag(out selfClosing) == endTag)  
  184.                     return;  
  185.                 // Use recursion to consume nested tags  
  186.                 if (!selfClosing && !tag.StartsWith("/"))  
  187.                     EatInnerContent(tag);  
  188.             }  
  189.             else MoveAhead();  
  190.         }  
  191.     }  
  192.   
  193.     // Returns true if the current position is at the end of  
  194.     // the string  
  195.     protected bool EndOfText  
  196.     {  
  197.         get { return (_pos >= _html.Length); }  
  198.     }  
  199.   
  200.     // Safely returns the character at the current position  
  201.     protected char Peek()  
  202.     {  
  203.         return (_pos < _html.Length) ? _html[_pos] : (char)0;  
  204.     }  
  205.   
  206.     // Safely advances to current position to the next character  
  207.     protected void MoveAhead()  
  208.     {  
  209.         _pos = Math.Min(_pos + 1, _html.Length);  
  210.     }  
  211.   
  212.     // Moves the current position to the next non-whitespace  
  213.     // character.  
  214.     protected void EatWhitespace()  
  215.     {  
  216.         while (Char.IsWhiteSpace(Peek()))  
  217.             MoveAhead();  
  218.     }  
  219.   
  220.     // Moves the current position to the next non-whitespace  
  221.     // character or the start of the next line, whichever  
  222.     // comes first  
  223.     protected void EatWhitespaceToNextLine()  
  224.     {  
  225.         while (Char.IsWhiteSpace(Peek()))  
  226.         {  
  227.             char c = Peek();  
  228.             MoveAhead();  
  229.             if (c == '\n')  
  230.                 break;  
  231.         }  
  232.     }  
  233.   
  234.     // Moves the current position past a quoted value  
  235.     protected void EatQuotedValue()  
  236.     {  
  237.         char c = Peek();  
  238.         if (c == '"' || c == '\'')  
  239.         {  
  240.             // Opening quote  
  241.             MoveAhead();  
  242.             // Find end of value  
  243.             int start = _pos;  
  244.             _pos = _html.IndexOfAny(new char[] { c, '\r''\n' }, _pos);  
  245.             if (_pos < 0)  
  246.                 _pos = _html.Length;  
  247.             else  
  248.                 MoveAhead();    // Closing quote  
  249.         }  
  250.     }  
  251.   
  252.     /// <summary>  
  253.     /// A StringBuilder class that helps eliminate excess whitespace.  
  254.     /// </summary>  
  255.     protected class TextBuilder  
  256.     {  
  257.         private StringBuilder _text;  
  258.         private StringBuilder _currLine;  
  259.         private int _emptyLines;  
  260.         private bool _preformatted;  
  261.   
  262.         // Construction  
  263.         public TextBuilder()  
  264.         {  
  265.             _text = new StringBuilder();  
  266.             _currLine = new StringBuilder();  
  267.             _emptyLines = 0;  
  268.             _preformatted = false;  
  269.         }  
  270.   
  271.         /// <summary>  
  272.         /// Normally, extra whitespace characters are discarded.  
  273.         /// If this property is set to true, they are passed  
  274.         /// through unchanged.  
  275.         /// </summary>  
  276.         public bool Preformatted  
  277.         {  
  278.             get  
  279.             {  
  280.                 return _preformatted;  
  281.             }  
  282.             set  
  283.             {  
  284.                 if (value)  
  285.                 {  
  286.                     // Clear line buffer if changing to  
  287.                     // preformatted mode  
  288.                     if (_currLine.Length > 0)  
  289.                         FlushCurrLine();  
  290.                     _emptyLines = 0;  
  291.                 }  
  292.                 _preformatted = value;  
  293.             }  
  294.         }  
  295.   
  296.         /// <summary>  
  297.         /// Clears all current text.  
  298.         /// </summary>  
  299.         public void Clear()  
  300.         {  
  301.             _text.Length = 0;  
  302.             _currLine.Length = 0;  
  303.             _emptyLines = 0;  
  304.         }  
  305.   
  306.         /// <summary>  
  307.         /// Writes the given string to the output buffer.  
  308.         /// </summary>  
  309.         /// <param name="s"></param>  
  310.         public void Write(string s)  
  311.         {  
  312.             foreach (char c in s)  
  313.                 Write(c);  
  314.         }  
  315.   
  316.         /// <summary>  
  317.         /// Writes the given character to the output buffer.  
  318.         /// </summary>  
  319.         /// <param name="c">Character to write</param>  
  320.         public void Write(char c)  
  321.         {  
  322.             if (_preformatted)  
  323.             {  
  324.                 // Write preformatted character  
  325.                 _text.Append(c);  
  326.             }  
  327.             else  
  328.             {  
  329.                 if (c == '\r')  
  330.                 {  
  331.                     // Ignore carriage returns. We'll process  
  332.                     // '\n' if it comes next  
  333.                 }  
  334.                 else if (c == '\n')  
  335.                 {  
  336.                     // Flush current line  
  337.                     FlushCurrLine();  
  338.                 }  
  339.                 else if (Char.IsWhiteSpace(c))  
  340.                 {  
  341.                     // Write single space character  
  342.                     int len = _currLine.Length;  
  343.                     if (len == 0 || !Char.IsWhiteSpace(_currLine[len - 1]))  
  344.                         _currLine.Append(' ');  
  345.                 }  
  346.                 else  
  347.                 {  
  348.                     // Add character to current line  
  349.                     _currLine.Append(c);  
  350.                 }  
  351.             }  
  352.         }  
  353.   
  354.         // Appends the current line to output buffer  
  355.         protected void FlushCurrLine()  
  356.         {  
  357.             // Get current line  
  358.             string line = _currLine.ToString().Trim();  
  359.   
  360.             // Determine if line contains non-space characters  
  361.             string tmp = line.Replace(" ", String.Empty);  
  362.             if (tmp.Length == 0)  
  363.             {  
  364.                 // An empty line  
  365.                 _emptyLines++;  
  366.                 if (_emptyLines < 2 && _text.Length > 0)  
  367.                     _text.AppendLine(line);  
  368.             }  
  369.             else  
  370.             {  
  371.                 // A non-empty line  
  372.                 _emptyLines = 0;  
  373.                 _text.AppendLine(line);  
  374.             }  
  375.   
  376.             // Reset current line  
  377.             _currLine.Length = 0;  
  378.         }  
  379.   
  380.         /// <summary>  
  381.         /// Returns the current output as a string.  
  382.         /// </summary>  
  383.         public override string ToString()  
  384.         {  
  385.             if (_currLine.Length > 0)  
  386.                 FlushCurrLine();  
  387.             return _text.ToString();  
  388.         }  
  389.     }  
  390. }  
  391.   
  392.   
  393.   
  394.   
  395.   
  396. //2、提取html的正文 类  
  397. using System;  
  398.  using System.Text;  
  399.  namespace HtmlStrip  
  400.  {  
  401.      class MainClass  
  402.      {  
  403.          public static void Main (string[] args)  
  404.          {  
  405.              string str = "<div>abc</div><span>efg</span><br /><script>888</script><!--<PA>WW</PA-->oo";  
  406.              //System.IO.StreamReader rd=new System.IO.StreamReader ("/home/lx/test.html");  
  407.              //str=rd.ReadToEnd ();  
  408.              HtmlParser t = new HtmlParser (str); //  
  409.              t.KeepTag (new string[] { "br" }); //设置br标签不过虑  
  410.              Console.Write (t.Text ());  
  411.          }  
  412.            
  413.            
  414.            
  415.      }  
  416.      class HtmlParser  
  417.      {  
  418.          private string[] htmlcode; //把html转为数组形式用于分析  
  419.          private StringBuilder result = new StringBuilder ();  //输出的结果  
  420.          private int seek; //分析文本时候的指针位置  
  421.          private string[] keepTag;  //用于保存要保留的尖括号内容  
  422.          private bool _inTag;  //标记现在的指针是不是在尖括号内  
  423.          private bool needContent = true;  //是否要提取正文  
  424.          private string tagName;  //当前尖括号的名字  
  425.          private string[] specialTag = new string[] { "script""style""!--" };  //特殊的尖括号内容,一般这些标签的正文是不要的  
  426.            
  427.          /// <summary>  
  428.          /// 当指针进入尖括号内,就会触发这个属性。这里主要逻辑是提取尖括号里的标签名字  
  429.          /// </summary>  
  430.          public bool inTag {  
  431.              get { return _inTag; }  
  432.              set {  
  433.                  _inTag = value;  
  434.                  if (!value)  
  435.                      return;  
  436.                  bool ok = true;  
  437.                  tagName = "";  
  438.                  while (ok) {  
  439.                      string word = read ();  
  440.                      if (word != " " && word != ">") {  
  441.                          tagName += word;  
  442.                      } else if (word == " " && tagName.Length > 0) {  
  443.                          ok = false;  
  444.                      } else if (word == ">") {  
  445.                          ok = false;  
  446.                          inTag = false;  
  447.                          seek -= 1;  
  448.                      }  
  449.                  }  
  450.              }  
  451.          }  
  452.          /// <summary>  
  453.          /// 初始化类  
  454.          /// </summary>  
  455.          /// <param name="html">  
  456.          ///  要分析的html代码  
  457.          /// </param>  
  458.          public HtmlParser (string html)  
  459.          {  
  460.              htmlcode = new string[html.Length];  
  461.              for (int i = 0; i < html.Length; i++) {  
  462.                  htmlcode[i] = html[i].ToString ();  
  463.              }  
  464.              KeepTag (new string[] {  });  
  465.          }  
  466.          /// <summary>  
  467.          /// 设置要保存那些标签不要被过滤掉  
  468.          /// </summary>  
  469.          /// <param name="tags">  
  470.          ///  
  471.          /// </param>  
  472.          public void KeepTag (string[] tags)  
  473.          {  
  474.              keepTag = tags;  
  475.          }  
  476.            
  477.          /// <summary>  
  478.          ///   
  479.          /// </summary>  
  480.          /// <returns>  
  481.          /// 输出处理后的文本  
  482.          /// </returns>  
  483.          public string Text ()  
  484.          {  
  485.              int startTag = 0;  
  486.              int endTag = 0;  
  487.              while (seek < htmlcode.Length) {  
  488.                  string word = read ();  
  489.                  if (word.ToLower () == "<") {  
  490.                      startTag = seek;  
  491.                      inTag = true;  
  492.                  } else if (word.ToLower () == ">") {  
  493.                      endTag = seek;  
  494.                      inTag = false;  
  495.                      if (iskeepTag (tagName.Replace ("/"""))) {  
  496.                          for (int i = startTag - 1; i < endTag; i++) {  
  497.                              result.Append (htmlcode[i].ToString ());  
  498.                          }  
  499.                      } else if (tagName.StartsWith ("!--")) {  
  500.                          bool ok = true;  
  501.                          while (ok) {  
  502.                              if (read () == "-") {  
  503.                                  if (read () == "-") {  
  504.                                      if (read () == ">") {  
  505.                                          ok = false;  
  506.                                      } else {  
  507.                                          seek -= 1;  
  508.                                      }  
  509.                                  }  
  510.                              }  
  511.                          }  
  512.                      } else {  
  513.                          foreach (string str in specialTag) {  
  514.                              if (tagName == str) {  
  515.                                  needContent = false;  
  516.                                  break;  
  517.                              } else  
  518.                                  needContent = true;  
  519.                          }  
  520.                      }  
  521.                  } else if (!inTag && needContent) {  
  522.                      result.Append (word);  
  523.                  }  
  524.                    
  525.              }  
  526.              return result.ToString ();  
  527.          }  
  528.          /// <summary>  
  529.          /// 判断是否要保存这个标签  
  530.          /// </summary>  
  531.          /// <param name="tag">  
  532.          /// A <see cref="System.String"/>  
  533.          /// </param>  
  534.          /// <returns>  
  535.          /// A <see cref="System.Boolean"/>  
  536.          /// </returns>  
  537.          private bool iskeepTag (string tag)  
  538.          {  
  539.              foreach (string ta in keepTag) {  
  540.                  if (tag.ToLower () == ta.ToLower ()) {  
  541.                      return true;  
  542.                  }  
  543.              }  
  544.              return false;  
  545.          }  
  546.          private string read ()  
  547.          {  
  548.              return htmlcode[seek++];  
  549.          }  
  550.    
  551.      }  
  552.  }  
  553.    

 

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

posted @ 2013-07-23 13:35  Chester.Y.Zhang  阅读(817)  评论(0编辑  收藏  举报