gpt4 book ai didi

string - 如何在 C# 中优化这个 UserAgent 解析器 for 循环?

转载 作者:行者123 更新时间:2023-12-02 09:50:38 33 4
gpt4 key购买 nike

我正在编写一个 C# 程序来分析 Web 服务器日志的 UserAgent 列中的浏览器数量。我希望输出浏览器类型、浏览器主要版本和点击次数。

我该如何优化它?

我使用正则表达式将 UserAgent 字符串与预定义字符串进行比较,以测试 Firefox、Opera 等。然后使用正则表达式消除可能的不匹配。然后我使用正则表达式来获取主要版本。我使用一个结构来保存每个浏览器的此信息:

private struct Browser
{
public int ID;
public string name;
public string regex_match;
public string regex_not;
public string regex_version;
public int regex_group;
}

然后,我加载浏览器信息并循环遍历 UserAgent 的所有记录:

Browser[] browsers = new Browser[5];
for (int i = 0; i < 5; i++)
{
browsers[i].ID = i;
}
browsers[0].name = "Firefox";
browsers[1].name = "Opera";
browsers[2].name = "Chrome";
browsers[3].name = "Safari";
browsers[4].name = "Internet Explorer";
browsers[0].regex_match = "(?i)firefox/([\\d\\.]*)";
browsers[1].regex_match = "(?i)opera/([\\d\\.]*)";
browsers[2].regex_match = "(?i)chrome/([\\d\\.]*)";
browsers[3].regex_match = "(?i)safari/([\\d\\.]*)";
browsers[4].regex_match = "(?i)msie([+_ ]|)([\\d\\.]*)";
browsers[0].regex_not = "(?i)flock";
browsers[1].regex_not = "";
browsers[2].regex_not = "";
browsers[3].regex_not = "(?i)android|arora|chrome|shiira";
browsers[4].regex_not = "(?i)webtv|omniweb|opera";
browsers[0].regex_version = "(?i)firefox/([\\d\\.]*)";
browsers[1].regex_version = "(?i)opera/([\\d\\.]*)";
browsers[2].regex_version = "(?i)chrome/([\\d\\.]*)";
browsers[3].regex_version = "(?i)version/([\\d\\.]*)";
browsers[4].regex_version = "(?i)msie([+_ ]|)([\\d\\.]*)";
browsers[0].regex_group = 1;
browsers[1].regex_group = 1;
browsers[2].regex_group = 1;
browsers[3].regex_group = 1;
browsers[4].regex_group = 2;
Dictionary<string, int> browser_counts = new Dictionary<string, int>();
for (int i = 0; i < 65000; i++)
{
foreach (Browser b in browsers)
{
if (Regex.IsMatch(csUserAgent[i], b.regex_match))
{
if (b.regex_not != "")
{
if (Regex.IsMatch(csUserAgent[i], b.regex_not))
{
continue;
}
}
string strBrowser = b.name;
if (b.regex_version != "")
{
string strVersion = Regex.Match(csUserAgent[i], b.regex_version).Groups[b.regex_group].Value;
int intPeriod = strVersion.IndexOf('.');
if (intPeriod > 0)
{
strBrowser += " " + strVersion.Substring(0, intPeriod);
}
}
if (!browser_counts.ContainsKey(strBrowser))
{
browser_counts.Add(strBrowser, 1);
}
else
{
browser_counts[strBrowser]++;
}
break;
}
}
}

最佳答案

你可以

  • 构造一个哈希表或最常匹配的用户代理并避免匹配正则表达式。

  • 存储编译新的Regex(pattern, RegexOptions.Compiled),而不仅仅是pattern

  • 将正则表达式合并为一个正则表达式,并利用 RegexOptions.Compiled 和 RegexOptions.CultureInvariantIgnoreCase

  • 而不是匹配两次(一次使用 IsMatch 一次使用 Matches)匹配一次(Matches)并检查 MatchCollection 是否匹配为空

这只是一个起点 - 我可能会在阅读代码时提出更多想法:)

编辑还有一个:

  • 避免使用另一个正则表达式解析版本 - 只有 safari 需要根据您的配置进行特殊处理。尝试使用与 browserid 相同的正则表达式来“捕获”版本。 (我现在只是为 Safari 破例)
<小时/>

例如你可以有一个像这样的静态正则表达式实例:

private static readonly Regex _regex = new Regex(
"(?i)"
+ "(?<browserid>(?:firefox/|opera/|chrome/|chrome/|safari/|msie[+_ ]?))"
+ "(?<version>[\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);

您可以使用 match.Groups["browserid"]match.Groups["version"] 方便地访问适当的子组。这几乎消除了浏览器结构列表的所有使用。

它唯一仍然满足的是排除正则表达式(regex_not)。不过,我建议首先使用单个正正则表达式重新进行分析,并在煎小鱼之前看看是否仍然存在性能问题。

基准

我编写了一个基准测试(见下文)。我将逐步更新此内容,直到我失去兴趣:)(我知道我的数据集不具有代表性。如果您上传文件,我将用它来测试它)

  1. 用单个静态编译的正则表达式替换单独的正则表达式,速度从 14 秒提升到 2.1 秒(加速 6 倍); 这只是替换了最外层的匹配

  2. 用预编译的正则表达式替换 regex_not/regex_version 对我的测试集没有太大影响(但我没有实际匹配的用户代理,所以这是有道理的)

.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;


public class Program
{
private struct Browser
{
public int ID;
public string name;
public Regex regex_match, regex_not, regex_version;
public int regex_group;
}

private static readonly Regex _regex = new Regex("(?i)"
+ "(?<browserid>(?:firefox/|opera/|chrome/|chrome/|safari/|msie[+_ ]?))"
+ "(?<version>[\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);

public static void Main(string[] args)
{

Browser[] browsers = new Browser[5];
for (int i = 0; i < 5; i++)
{
browsers[i].ID = i;
}
browsers[0].name = "Firefox";
browsers[1].name = "Opera";
browsers[2].name = "Chrome";
browsers[3].name = "Safari";
browsers[4].name = "Internet Explorer";
browsers[0].regex_match = new Regex("(?i)firefox/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_match = new Regex("(?i)opera/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[2].regex_match = new Regex("(?i)chrome/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[3].regex_match = new Regex("(?i)safari/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_match = new Regex("(?i)msie([+_ ]|)([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
// OPTIMIZATION #2
browsers[0].regex_not = new Regex("(?i)flock", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_not = null;
browsers[2].regex_not = null;
browsers[3].regex_not = new Regex("(?i)android|arora|chrome|shiira", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_not = new Regex("(?i)webtv|omniweb|opera", RegexOptions.Compiled | RegexOptions.CultureInvariant);
// OPTIMIZATION #2
browsers[0].regex_version = new Regex("(?i)firefox/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[1].regex_version = new Regex("(?i)opera/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[2].regex_version = new Regex("(?i)chrome/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[3].regex_version = new Regex("(?i)version/([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[4].regex_version = new Regex("(?i)msie([+_ ]|)([\\d\\.]*)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
browsers[0].regex_group = 1;
browsers[1].regex_group = 1;
browsers[2].regex_group = 1;
browsers[3].regex_group = 1;
browsers[4].regex_group = 2;
Dictionary<string, int> browser_counts = new Dictionary<string, int>();

var lookupBrowserId = new Dictionary<string, int> {
{ "firefox/", 0 },
{ "opera/", 1 },
{ "chrome/", 2 },
{ "safari/", 3 },
{ "msie+", 4 },
{ "msie_", 4 },
{ "msie ", 4 },
{ "msie", 4 },
};

for (int i=1; i<20; i++)
foreach (var line in System.IO.File.ReadAllLines("/etc/dictionaries-common/words"))
{
// OPTIMIZATION #1 START
Match match = _regex.Match(line);

{
if (match.Success)
{
Browser b = browsers[lookupBrowserId[match.Groups["browserid"].Value]];
// OPTIMIZATION #1 END

// OPTIMIZATION #2
if (b.regex_not != null && b.regex_not.IsMatch(line))
continue;

string strBrowser = b.name;
if (b.regex_version != null)
{
// OPTIMIZATION #2
string strVersion = b.regex_version.Match(line).Groups[b.regex_group].Value;
int intPeriod = strVersion.IndexOf('.');
if (intPeriod > 0)
{
strBrowser += " " + strVersion.Substring(0, intPeriod);
}
}
if (!browser_counts.ContainsKey(strBrowser))
{
browser_counts.Add(strBrowser, 1);
}
else
{
browser_counts[strBrowser]++;
}
break;
}
}
}
}
}

关于string - 如何在 C# 中优化这个 UserAgent 解析器 for 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7404634/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com