如何从HTML文件中的一个文本块解析一些字符串?

时间:2014-07-12 08:36:29

标签: c# html .net

我有这段代码:

public static void CreateTextList(string filePath)
        {
            List<string> text;

            text = new List<string>();
            var htmlDoc = new HtmlAgilityPack.HtmlDocument();
            htmlDoc.OptionFixNestedTags = true;
            htmlDoc.Load(filePath, System.Text.Encoding.GetEncoding(65001));

            if (htmlDoc.DocumentNode != null)
            {
                var nodes = htmlDoc.DocumentNode.SelectNodes("//a/b");
                foreach (var node in nodes)
                {
                    text.Add(node.InnerText);
                }
            }
            TextList = Filters.filterNumbers(text);
        }

Filepath例如:d:\rotterhtml\rotterscoops.html

现在我要从HTML中提取的文本中的块是:

<body onmousemove="overhere()">
<a  onmouseover="EnterContent('ToolTip','אבו זוהרי: &rsquo;&rsquo; בשעות הקרובות הפתעה לישראל &rsquo;&rsquo;','<u><span style=color:#000099;>כתב: כוח הימין   בתאריך: 11.07.14  שעה: 17:41</span></u><br>איום של הדובר הזרוע הצבאית של החמאס אבו זוהרי לקראת השבת:<br>&quot; בשעות הקרובות נכניס אלמנטים חדשים ללחימה שיגרמו לתושבי ישראל להתבלבל &quot;<br><br...'); Activate();" onmouseout="deActivate()" href="javascript:void(0)"> 
<img src="http://rotter.net/forum/Images/hot_icon_news.gif" border="0"></a></TD><TD ALIGN="right" VALIGN="TOP" WIDTH="55%">
<FONT CLASS='text15bn'><FONT FACE="Arial">
<a href="http://rotter.net/cgi-bin/forum/dcboard.cgi?az=read_count&om=116347&forum=scoops1"><b>

现在我这样做的方法是只提取文字:בשעות הקרובות הפתעה לישראל

但是现在我想从块中提取另外两部分:

First this part: בתאריך: 11.07.14  שעה: 17:41 
Seconde this part: http://rotter.net/cgi-bin/forum/dcboard.cgi?az=read_count&om=116347&forum=scoops1

并将它们添加到List文本中。 所以最后在文本中我会看到前3个索引:

אבו זוהרי: בשעות הקרובות הפתעה לישראל
בתאריך: 11.07.14  שעה: 17:41
http://rotter.net/cgi-bin/forum/dcboard.cgi?az=read_count&om=116347&forum=scoops1

然后在下一个循环迭代中再次索引3 4 5也同样提取文本部分的日期时间部分和链接部分。

修改

尝试过Corey解决方案。在课堂上我做了:

string t = File.ReadAllText(filePath);

现在包含html文件的内容。 然后在底部我做了:

// Combined regular expression pattern
            var pattern = @"&rsquo;&rsquo;(.*?)&rsquo;&rsquo;.*?([^\s]*?:\s*\d+\.\d+\.\d+\s+[^\s]+:\s\d+:\d+).*?<a href=""(http://.*?)""";
            // The 'SingleLine' option lets us work across the whole text
            var re = new Regex(pattern, RegexOptions.Singleline);
            // Run the RE against the source
            var m = re.Match(t);
            // Combine the capture groups into a string 
            string result = string.Join("\n", new string[] { m.Groups[0].ToString(), m.Groups[1].ToString(), m.Groups[2].ToString() });

我得到的结果是:

&rsquo;&rsquo;ל במבצע &rsquo;&rsquo;צוק איתן&rsquo;&rsquo; יומן מלחמה -היום החמישי.','<u><span style=color:#000099;>כתב: ש_ש   בתאריך: 12.07.14  שעה: 11:06</span></u><br>אשכול מרכזי לפעילות צה&rsquo;&rsquo;ל במבצע &rsquo;&rsquo;צוק איתן&rsquo;&rsquo; יומן מלחמה -היום החמישי.  <br> <br>      <br>מבצע &quot;צוק איתן&quot; נ...'); Activate();" onmouseout="deActivate()" href="javascript:void(0)"> 
<img src="http://rotter.net/forum/Images/hot_icon_general.gif" border="0"></a></TD><TD ALIGN="right" VALIGN="TOP" WIDTH="55%">
<FONT CLASS='text15bn'><FONT FACE="Arial">
<a href="http://rotter.net/cgi-bin/forum/dcboard.cgi?az=read_count&om=116498&forum=scoops1"
ל במבצע 
בתאריך: 12.07.14  שעה: 11:06

我应该得到的是:

אבו זוהרי: בשעות הקרובות הפתעה לישראל
בתאריך: 11.07.14  שעה: 17:41
http://rotter.net/cgi-bin/forum/dcboard.cgi?az=read_count&om=116347&forum=scoops1

1 个答案:

答案 0 :(得分:0)

这正是正则表达式的用武之地。

您要提取的每个文本片段都可以通过正则表达式在上下文中进行标识,该表达式仅匹配该片段而不再匹配。这些是我根据上面的HTML示例提出的正则表达式:

&rsquo;&rsquo;(.*?)&rsquo;&rsquo;
([^\s]*?:\s*\d+\.\d+\.\d+\s+[^\s]+:\s\d+:\d+)
<a href=""(http://.+?)""

每个匹配您指定的输出行之一,并在您提供的示例中唯一匹配。他们可能需要进行一些调整以匹配其他文本,但希望不要太多。 ()个字符包含您实际感兴趣的文本,以及标识周围文本的外部内容。

您可以针对HTML源运行每个正则表达式,并可能获得您期望的输出。但是,如果文件中有其他链接,或者您希望确保所有三个项目都以正确的顺序存在,则可以将三个项目折叠为单个正则表达式。如果任何项目缺失或格式错误,则不匹配,只有当所有三个术语都按照提供的顺序匹配页面上的文本时才会匹配。

以下是代码:

// Combined regular expression pattern
var pattern = @"&rsquo;&rsquo;(.*?)&rsquo;&rsquo;.*?([^\s]*?:\s*\d+\.\d+\.\d+\s+[^\s]+:\s\d+:\d+).*?<a href=""(http://.*?)""";
// The 'SingleLine' option lets us work across the whole text
var re = new Regex(pattern, RegexOptions.Singleline);
// Run the RE against the source
var m = re.Match(html);
// Combine the capture groups into a string 
string result = string.Join("\n", new string[] { m.Groups[1], m.Groups[2], m.Groups[3] });

如果您的要求不是给定订单中的所有部分,还有其他一些方法可以做到这一点,但由于您正在处理网页,因此可能会发生这种情况相当一致。


一句警告:正则表达式很容易出错。

有句老话:

  

有些人在面对问题时会想到,我知道,我会使用正则表达式。&#34;

     

现在他们有两个问题。

通常它是真的。我上面写的正则表达式适用于您已经给出的示例,但可能会失败 - 或者更糟糕的是,给出错误的结果 - 取决于页面的真实内容。在决定将此解决方案用于生产代码之类的任何内容之前,请确保您了解他们正在做什么,他们的限制是什么,以及他们如何出错。从长远来看,它会让你感到悲伤。