正则表达式有问题

时间:2010-12-04 21:03:51

标签: c# regex

我是正则表达式的总菜鸟,需要解析一些html。我正在寻找个别类别。以下是html的样子:

<p>Categories: 
        <a href="/some/URL/That/I/dont/need">Category1</a>  | 
        <a href="/could/be/another/URL/That/I/dont/need">Category2</a> 
</p> 

可能有1-5个类别。我需要的是“Category1或Category2等”

这个项目使用Visual Studio 2010在c#中。目前我所拥有的是:

private static readonly Regex _categoriesRegex = new Regex("(<p>Categories:)((/w/.?<Categories>.*?).*?)(</p>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);

我知道我可能会离开,但想知道是否有人能够至少引导我朝着正确的方向前进。

3 个答案:

答案 0 :(得分:6)

请勿使用正则表达式执行此类任务,请改用专用工具。您最好的选择可能是使用HTML Agility Pack


编辑:这是使用HTML Agility Pack(用LINQPad编写)的一个例子:

void Main()
{
    var doc = new HtmlDocument();
    doc.Load(@"D:\tmp\foobar.html");
    var query =
        from p in doc.DocumentNode.Descendants("p")
        where p.InnerText.StartsWith("Categories:")
        from a in p.Elements("a")
        select a.InnerText;

    query.Dump();
}

它返回:

Category1
Category2

我应该注意到这是我第一次尝试使用HAP,我很惊喜它是多么容易(编写上面的代码花了大约3分钟)。该API与Linq to XML非常相似,如果您对Linq感到满意,这将非常直观。

答案 1 :(得分:1)

通常会针对这些类型的问题建议使用HTML Agility Pack(HAP),Thomas' solution很棒,但我通常不是100%如果你可以保证那么您的输入结构良好,您想要的结果很简单。如果是这种情况,那么通常可以使用LINQ to XML而不是将HAP引入到项目中。我在下面演示了这种方法。我还包括一个正则表达式方法,因为你的请求不是太疯狂,因为非嵌套输入很容易处理。

我建议您坚持使用LINQ解决方案,因为它易于维护且易于理解。添加正则表达式仅用于演示如何执行此操作并解决原始问题。

string input = @"<p>Categories: 
        <a href=""/some/URL/That/I/dont/need"">Category1</a>  | 
        <a href=""/could/be/another/URL/That/I/dont/need"">Category2</a> 
</p>";

// LINQ to XML approach for well formed HTML
var xml = XElement.Parse(input);
var query = xml.Elements("a").Select(e => e.Value);
foreach (var item in query)
{
    Console.WriteLine(item);
}

// regex solution
string pattern = @"Categories:(?:[^<]+<a[^>]+>([^<]+)</a>)+";

Match m = Regex.Match(input, pattern);
if (m.Success)
{
    foreach (Capture c in m.Groups[1].Captures)
    {
        Console.WriteLine(c.Value);    
    }
}

答案 2 :(得分:0)

Addint一点点@Thomas Levesque的答案(这是正确的方法):

如果您想获取<a>标记之间的链接而不是文字,则只需执行以下操作:

    var query =
        from p in doc.DocumentNode.Descendants("p")
        where p.InnerText.StartsWith("Categories:")
        from a in p.Elements("a")
        select a.Attributes["href"].Value;

编辑:如果您不熟悉LINQ语法,可以使用以下方法:

var nodes = doc.DocumentNode.SelectNodes("//p"); //Here I get all the <p> tags in the document
if (nodes != null)
{
    foreach (var n in nodes)
    {
        if (n.InnerText.StartsWith("Categories:")) //If the <p> tag we need was found
        {
            foreach (var a in n.SelectNodes("./a[@href]")) //Iterating through all <a> tags that are next to the <p> tag (childs)
            {
                //It will print something like: "Name: Category1        Link: /some/URL/That/I/dont/need
                Console.WriteLine("Name: {0} \t Link: {1}", a.InnerText, a.Attributes["href"].Value; 
            }
            break;
        }
    }
}