来自网站的C#正则表达式数据

本文关键字:正则表达式 数据 网站 | 更新日期: 2023-09-27 18:21:48

我正在尝试为一个名为Tibia的游戏添加插件。

在他们的网站Tibia.com上,你可以搜索人们并查看他们的死亡情况。

例如:

http://www.tibia.com/community/?subtopic=characters&name=Kixus

现在我想通过在我的C#应用程序中使用Regex来读取死亡数据。

但我似乎无法解决,我已经在上花了好几个小时了

http://myregextester.com/index.php

我使用的表达式是:

<tr bgcolor=(?:"#D4C0A1"|"#F1E0C6") ><td width="25%" valign="top" >(.*?)?#160;CET</td><td>((?:Died|Killed) at Level ([^ ]*)|and) by (?:<[^>]*>)?([^<]*).</td></tr>

但我无法让它发挥作用。

我想要时间戳、生物/玩家等级和生物/玩家名称

提前谢谢。

-问候

来自网站的C#正则表达式数据

使用正则表达式解析HTML是个坏主意。对于这份工作来说,它们是一个非常糟糕的工具。如果您正在解析HTML,请使用HTML解析器。

对于.NET,通常的建议是使用HTML敏捷包。

正如Joe White所建议的,如果您使用HTML解析器来完成此任务,那么您将拥有一个更加健壮的实现。StackOverflow对此有很多支持:例如,请参阅此处。

如果您真的必须使用regexs

我建议将您的解决方案分解为更简单的regexs,可以使用自上而下的解析方法来应用该regexs以获得结果。

例如:

  1. 在整个页面上使用与字符表匹配的正则表达式

    我建议在表前后匹配最短的唯一字符串,而不是表本身,并使用组捕获表,因为这样可以避免处理嵌套表的可能性。

  2. 在与表行匹配的字符表上使用正则表达式

  3. 在第一个单元格上使用正则表达式来匹配日期
  4. 在第二个单元格中使用正则表达式来匹配链接
  5. 在第二个单元格中使用正则表达式来匹配玩家级别
  6. 如果是生物,在第二个单元格上使用正则表达式匹配杀手名称(单元格中没有链接)

如果站点显著更改其Html结构,这将更易于维护。

使用HtmlAgilityKit的完整工作实现

您可以从CodePlex上的HtmlAgilityKit站点下载库。

// This class is used to represent the extracted details
public class DeathDetails
{
    public DeathDetails()
    {
        this.KilledBy = new List<string>();
    }
    public string DeathDate { get; set; }
    public List<String> KilledBy { get; set; }
    public int PlayerLevel { get; set; }
}
public class CharacterPageParser
{
    public string CharacterName { get; private set; }
    public CharacterPageParser(string characterName)
    {
        this.CharacterName = characterName;
    }
    public List<DeathDetails> GetDetails()
    {
        string url = "http://www.tibia.com/community/?subtopic=characters&name=" + this.CharacterName;
        string content = GetContent(url);
        HtmlDocument document = new HtmlDocument();
        document.LoadHtml(content);
        HtmlNodeCollection tables = document.DocumentNode.SelectNodes("//div[@id='characters']//table");
        HtmlNode table = GetCharacterDeathsTable(tables);
        List<DeathDetails> deaths = new List<DeathDetails>();
        for (int i = 1; i < table.ChildNodes.Count; i++)
        {
            DeathDetails details = BuildDeathDetails(table, i);
            deaths.Add(details);
        }
        return deaths;
    }
    private static string GetContent(string url)
    {
        using (System.Net.WebClient c = new System.Net.WebClient())
        {
            string content = c.DownloadString(url);
            return content;
        }
    }
    private static DeathDetails BuildDeathDetails(HtmlNode table, int i)
    {
        DeathDetails details = new DeathDetails();
        HtmlNode tableRow = table.ChildNodes[i];
        //every row should have two cells in it
        if (tableRow.ChildNodes.Count != 2)
        {
            throw new Exception("Html format may have changed");
        }
        HtmlNode deathDateCell = tableRow.ChildNodes[0];
        details.DeathDate = System.Net.WebUtility.HtmlDecode(deathDateCell.InnerText);
        HtmlNode deathDetailsCell = tableRow.ChildNodes[1];
        // get inner text to parse for player level and or creature name
        string deathDetails = System.Net.WebUtility.HtmlDecode(deathDetailsCell.InnerText);
        // get player level using regex
        Match playerLevelMatch = Regex.Match(deathDetails, @" level (['d]+) ", RegexOptions.IgnoreCase);
        int playerLevel = 0;
        if (int.TryParse(playerLevelMatch.Groups[1].Value, out playerLevel))
        {
            details.PlayerLevel = playerLevel;
        }
        if (deathDetailsCell.ChildNodes.Count > 1)
        {
            // death details contains links which we can parse for character names
            foreach (HtmlNode link in deathDetailsCell.ChildNodes)
            {
                if (link.OriginalName == "a")
                {
                    string characterName = System.Net.WebUtility.HtmlDecode(link.InnerText);
                    details.KilledBy.Add(characterName);
                }
            }
        }
        else
        {
            // player was killed by a creature - capture creature name
            Match creatureMatch = Regex.Match(deathDetails, " by (.*)", RegexOptions.IgnoreCase);
            string creatureName = creatureMatch.Groups[1].Value;
            details.KilledBy.Add(creatureName);
        }
        return details;
    }
    private static HtmlNode GetCharacterDeathsTable(HtmlNodeCollection tables)
    {
        foreach (HtmlNode table in tables)
        {
            // Get first row
            HtmlNode tableRow = table.ChildNodes[0];
            // check to see if contains enough elements
            if (tableRow.ChildNodes.Count == 1)
            {
                HtmlNode tableCell = tableRow.ChildNodes[0];
                string title = tableCell.InnerText;
                // skip this table if it doesn't have the right title
                if (title == "Character Deaths")
                {
                    return table;
                }
            }
        }
        return null;
    }

还有一个使用中的例子:

 CharacterPageParser kixusParser = new CharacterPageParser("Kixus");
        foreach (DeathDetails details in kixusParser.GetDetails())
        {
            Console.WriteLine("Player at level {0} was killed on {1} by {2}", details.PlayerLevel, details.DeathDate, string.Join(",", details.KilledBy));
        }

您还可以使用Espresso工具来计算正确的正则表达式。

要正确地转义所有不是正则表达式组成部分的特殊字符,可以使用Regex。转义方法:

string escapedText = Regex.Escape("<td width='"25%'" valign='"top'" >");

试试这个:

http://jsbin.com/atupok/edit#javascript,html

并从那里继续。。。。我在这里做得最多:)

编辑

http://jsbin.com/atupok/3/edit

并开始使用这个工具

http://regexr.com?2vrmf

不是你的那个。