Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 高效的字符串匹配算法_C#_Algorithm - Fatal编程技术网

C# 高效的字符串匹配算法

C# 高效的字符串匹配算法,c#,algorithm,C#,Algorithm,我正在尝试建立一个高效的字符串匹配算法。这将在高容量环境中执行,因此性能至关重要 以下是我的要求: 给定域名,即www.example.com,确定它是否“匹配”条目列表中的一个 条目可能是绝对匹配,即www.example.com 条目可能包括通配符,即.*.example.com 通配符项从定义最严格的级别开始匹配。例如,*.example.com将匹配www.example.com、example.com和sub.www.example.com 未嵌入通配符条目,即sub.*。examp

我正在尝试建立一个高效的字符串匹配算法。这将在高容量环境中执行,因此性能至关重要

以下是我的要求:

  • 给定域名,即www.example.com,确定它是否“匹配”条目列表中的一个
  • 条目可能是绝对匹配,即www.example.com
  • 条目可能包括通配符,即.*.example.com
  • 通配符项从定义最严格的级别开始匹配。例如,*.example.com将匹配www.example.com、example.com和sub.www.example.com
  • 未嵌入通配符条目,即sub.*。example.com将不是条目
语言/环境:C#(.Net Framework 3.5)

我考虑过将条目(和域查找)拆分为数组,颠倒顺序,然后遍历数组。虽然准确,但感觉很慢

我考虑过正则表达式,但担心的是如何将条目列表准确地表示为正则表达式


我的问题:根据上面列出的描述,如果一个字符串(以域名的形式)与字符串列表中的任何一个匹配,那么什么是一种有效的方法呢?

我会使用正则表达式,只需确保将其编译一次(而不是反复计算)

你似乎有一套定义良好的规则,关于你认为是有效的输入——你可以考虑使用手写的。这样的解析器相对容易编写和优化。通常,您会让解析器输出一个描述输入的树结构——我将使用此树作为匹配例程的输入,该例程使用上面描述的规则,根据条目列表匹配树


这里有一个

看看

我将使用树结构来存储规则,其中每个树节点都是/包含一个字典

构建树,使“com”、“net”等为顶级条目,“example”为下一级条目,依此类推。您需要一个特殊的标志来说明节点是通配符

要执行查找,请按句点拆分字符串,然后向后迭代,根据输入导航树

这似乎与您所说的类似,但是假设每次运行时规则都不改变,那么使用基于缓存字典的树将比使用数组列表更快


此外,我不得不打赌这种方法比正则表达式更快。

不确定您对拆分和迭代的想法,但它似乎不会太慢:


如你所说,将域名拆分并反转。存储本质上可以是一棵树。使用哈希表存储TLD。例如,键应该是“com”,值应该是TLD下的子域哈希表,迭代为ad nauseum。

根据您的要求,我认为您正在考虑从字符串(TLD)的末尾到主机名的工作。您可以使用正则表达式,但由于您没有真正使用regexp的任何功能,我不明白您为什么要为此付出代价。如果反转字符串,则更明显的是,您实际上只是在寻找前缀匹配(“*.example.com”变为:“moc.elpmaxe”是我输入字符串的开头吗?),这当然不需要像regexp这样的繁重操作


您用来存储条目列表的结构在很大程度上取决于列表的大小及其变化的频率……对于一个庞大的稳定列表,树/trie可能是最有效的;一个经常变化的列表需要一个易于初始化/更新的结构,等等。如果没有更多信息,我不愿意推荐任何一种结构

假设规则如您所说:literal或以*开头

爪哇:

公共静态布尔匹配(字符串候选、列表规则){
for(字符串规则:规则){
if(规则开始时带“*”){
规则=规则。子字符串(2);
}
if(候选者姓名(规则)){
返回true;
}
}
返回false;
}
这将根据您拥有的规则数量进行缩放

编辑:

我想说清楚

当我说“对规则进行排序”时,我真正的意思是用规则字符创建一棵树

然后使用匹配字符串尝试遍历树(即,如果我有一个xyz字符串,则从x字符开始,然后查看它是否有一个y分支,然后是一个z子级)

对于“通配符”,我将使用相同的概念,但“向后”填充它,并与匹配候选的后面一起走

如果你有很多规则,我会对规则进行排序

对于非通配符匹配,您迭代每个字符以缩小可能的规则(即,如果它以“w”开头,则使用“w”规则,等等)


如果是通配符匹配,则执行完全相同的操作,但您使用的是“向后规则”列表,只需将字符串的结尾与规则的结尾进行匹配。

如果您希望自己滚动,我会将条目存储在树结构中。请参阅关于拼写检查,了解我的意思

我不会用“.”字符来标记结构,而是将每个条目视为一个完整的字符串。任何标记化的实现仍然必须在完整的字符集上进行字符串匹配,因此您最好一次完成所有操作

这与常规拼写检查树的唯一区别是:

  • 匹配需要反向进行
  • 您必须考虑通配符 要解决第2点,只需在测试结束时检查“*”字符

    一个简单的例子:

    参赛作品:

    *.fark.com
    www.cnn.com
    
    树:

    检查www.blog.fark.com需要在树中跟踪到第一个
    “*”
    。因为遍历在
    “*”
    上结束,所以存在匹配

    检查www.cern.com将在n,n,c,…中的第二个“n”失败,。。
    *.fark.com
    www.cnn.com
    
    m -> o -> c -> . -> k -> r -> a -> f -> . -> *
                    \
                     -> n -> n -> c -> . -> w -> w -> w