使用带有C#.Net的browscap.ini或xml

时间:2015-02-03 20:20:50

标签: c# .net regex browser-detection

我今天在C#的土地上。 我正在尝试编写一个接受用户代理字符串的函数,并返回一个对象,该对象至少为我提供了浏览器名称和版本。所以我尝试了this answer,但它报告Chrome为AppleMAC-Safari 5.0。误报最流行的浏览器并不是真的可以接受。

我可以访问browscap.ini或XML或JSON。好像我必须手动完成它,但这些文件中的正则表达式与C#中的正则表达式不兼容。这是一场噩梦。

我正在使用Visual Studio和.Net 3.5。

1 个答案:

答案 0 :(得分:2)

我很高兴你问这个问题!它一直困扰着我。基本上你要做的就是获取并解析其中一个browscap文件。我使用了XML文件。从那里,您必须根据用户代理字符串检查每个正则表达式模式。在XML文件中,这是每个browscapitem的“name”属性。

但是,文件中的模式必须转换为真正的正则表达式,因此C#将理解它们。这是您的问题所需的主要方法。其他一切只是解析不同的文件类型。

(我使用this code查看其他人如何使其在PHP中运行。)

public static Boolean BrowserPatternMatches(string pattern, string input)
{
    string patternConverted = "^" + pattern
                .Replace("\\", "\\\\")
                .Replace(".", "\\.")
                .Replace("?", ".")
                .Replace("*", ".*")
                .Replace("$", "\\$")
                .Replace("[", "\\[")
                .Replace("]", "\\]")
                .Replace("|", "\\|")
                .Replace("(", "\\(")
                .Replace(")", "\\)")
                .Replace("+", "\\+")
                .Replace("{", "\\{")
                .Replace("}", "\\}")
                .Replace("%", "\\%")
                + "$";
    Regex regex = new Regex(patternConverted);
    return regex.IsMatch(input);
}

这是你问题的关键。剩下的就是解析XML并获取这些值。这不是我的专业领域,所以我只是做了足够的功能。在我的班上,我有:

private Dictionary<string, Dictionary<string, string>> dic = new Dictionary<string, Dictionary<string, string>>();

private void FillDictionary()
{
    if (this.dic.Count == 0)
    {
        XmlTextReader reader = new XmlTextReader("browscap.xml");

        while (reader.Read())
        {
            if (reader.Name == "browscapitem")
            {
                string pattern = reader.GetAttribute("name");
                if (pattern != null)
                {
                    if (!this.dic.ContainsKey(pattern))
                    {
                        Dictionary<string, string> properties = new Dictionary<string, string>();
                        while (reader.Read())
                        {
                            if (reader.Name == "browscapitem")
                            {
                                break;
                            }
                            if (reader.GetAttribute("name") != null)
                            {
                                properties.Add(reader.GetAttribute("name").ToLower(), reader.GetAttribute("value"));
                            }
                        }
                        this.dic.Add(pattern, properties);
                    }
                }
            }
        }
    }
}

其余只是填写“父”属性的一些技巧。因此,一旦找到匹配项,您必须返回并查找其父项及其父项的父项等。

private Dictionary<string, string> GetBrowserProps(string parentId)
{
    return this.dic[parentId];
}

public Dictionary<string, string> GetBrowserObject(string uaString)
{
    this.FillDictionary();

    bool found = false;
    string foundKey = "";

    foreach (string pattern in this.dic.Keys)
    {
        if (!found)
        {
            found = RecordBrowsers.BrowserPatternMatches(pattern, uaString);
            if (found) { foundKey = pattern; break; }
        }
    }

    Dictionary<string, string> browserProps = new Dictionary<string, string>();
    if (foundKey != "")
    {
        browserProps = this.GetBrowserProps(foundKey);
        Dictionary<string, string> current = this.GetBrowserProps(foundKey);
        bool cont = current.ContainsKey("parent");
        while (cont)
        {
            Dictionary<string, string> parent = this.GetBrowserProps(current["parent"]);
            foreach (string s in parent.Keys)
            {
                if (!browserProps.ContainsKey(s))
                {
                    browserProps.Add(s, parent[s]);
                }
            }
            current = parent;
            cont = current.ContainsKey("parent");
        }
    }

    return browserProps;
}

以下是我测试的好方法:

Console.WriteLine("RecordBrowser started");

string[] strs = { "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.94 Safari/537.36", 
                    "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0",
                    "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.94 Safari/537.36 OPR/27.0.1689.66",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.94 Safari/537.36",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.8pre) Gecko/20070928 Firefox/2.0.0.7 Navigator/9.0RC1",
                    "Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20121202 Firefox/17.0 Iceweasel/17.0.1"};

string[] expectedResults = { "Chrome 40.0", "Firefox 35.0", "Opera 27.0", "Chrome 40.0", "Netscape 9.0", "Iceweasel 17.0" };

for(int i=0; i<strs.Length; i++)
{
    Dictionary<string, string> browserProps = this.GetBrowserObject(strs[i]);
    if (browserProps["comment"] == expectedResults[i])
    {
        Console.WriteLine("test " + i + " passed");
    }
    else
    {
        Console.WriteLine("test " + i + " failed");
    }
    Console.WriteLine("**********************************************************");
}
Console.WriteLine("DONE");