将一个String与一组通配符进行比较的最快方法

时间:2012-04-02 15:24:42

标签: c# string compare

我有一个字典,我的密钥是带有通配符的字符串。我想知道一个字符串是否与dictinary中的任何键匹配。

示例:

String str = "Really Large String";
Dictionary dic = new Dictionary<String, MyClass>();
dic.Add("First+Match*", new MyClass());
dic.Add("*Large*", new MyClass());

编辑: 我想做点什么:

foreach(var s in dic.Keys){
  if(str.Match(s))
    //Do Something
}

3 个答案:

答案 0 :(得分:2)

您可以使用RegEx,只需将带有通配符的字符串转换为正则表达式模式(我假设您要使用相当旧的标准“*”和“?”通配符):

public static string ToRegEx(string pattern)
{
    return Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".");
}

答案 1 :(得分:2)

为什么不,

var dic = Dictionary<Regex, MyClass>()
dic.Add(new Regex("..."), new MyClass)
....

foreach(var match in dic.Keys.Where(k => k.IsMatch(str)))
{
    var myClass = dic[match];
    ....
}

现在有一个问题,为什么要使用字典,为什么不扩展MyClass以匹配字符串本身,也许使用名为Predicate的{​​{1}}。

Match

修改

如果您只想要第一场比赛,则可以使用var matchers = new HashSet<MyClass>(); matchers.Add(new MyClass("some regex?"); .... foreach(var match in matchers.Where(Match(str))) { .... } 代替FirstOrDefault

Where

但是,这会使列表的顺序显着。

编辑2

部分实施var firstMatch = matchers.FirstOrDefault(Match(str)) if (firstMatch != null) { .... } 以包含MyClass谓词可能是......

Match

答案 2 :(得分:-1)

这个解释比我想要的要长一些,但在这样的情况下,完全理解幕后发生的事情是非常有用的。因为特定方法在源代码中看起来很有效并不意味着CPU以相同的方式看待它。当您担心逐字节执行速度时,您必须了解在实际执行操作的级别上发生的情况。超出这个级别的任何东西都只是语义,最终是美化的宏,它们无法准确描述你实际创建的内容。

Intel / AMD CPU有一组重复扫描指令,允许您设置指针,将一个字节放入寄存器,设置要扫描的字节数,以及CPU内部关闭并以扫描方式运行扫描单个内部指令,扫描字节为字节,直到找到匹配或不匹配(或计数器用完)。当计数器用完时,调整指针并处理“没有达到的标准;我跑出柜台!”可能是一个混乱的过程。条件;这不会直接影响您的代码,但如果您在循环中进行大量单独搜索,则可能会影响执行时间。因此,最小化实际搜索次数绝不是一个坏主意。这不是一个很大的因素,但它可以考虑。

在我自己的代码中,在大搜索的情况下,我在第一个字节向前扫描。将其作为任何进一步过程的起点进行匹配可以节省绝大部分时间,否则这些时间将通过比较每个字节而浪费。让CPU做到。 CPU必须做大量的工作,只是为了加载指令并准备好执行它,所以只要你能减少工作量,程序就会运行得更快。

这里的问题是你没有很多直接控制这些东西。无论你使用什么语言,最有可能使用最慢的蛮力方法:拿起一个字节,查看它,拿起下一个字节,哈欠打哈欠哈欠。如果你的语言是这样做的(大部分都是这样),那么编码方法的任何两个选择之间就没有太大区别了:它们已经全部停留在性能基础上。如果您处于可以插入汇编代码块的情况,那么您将获得巨大的收益。但大多数人都被禁止这样做,因为在1985年它被认为是非法的。当然要考虑32位和64位问题,但可以考虑这些问题。无论如何,最重要的是,如果你能确切地找到你的特定语言的作用,那就考虑到这一点。如果它正在进行比较字符串的狩猎方法,那么战斗就已经失败了,而你调整代码的大部分工作可能不会产生太大影响。