在大文本文件中搜索字符串的最快方法

时间:2016-06-22 22:47:48

标签: c# string file

为了查找相当大的文本文件中的字符串列表(最多1GB文本文件),可以实现的最快技术/算法是什么。 对于初学者,我使用C#并且能够实现逻辑(简单地通过匹配文件和字符串列表,每次都是字符串。这意味着文件将被读取 n 与" times相匹配的字符串数量,但由于我处理了大量文件,因此需要永久地运行它们并获得匹配。 即使它不是C#,我也可以接受任何建议。

详细说明,我有一个包含许多数字的文本文件(A),我有很多大文件(B)。我试图获取(A)中的每个元素,并逐行查看(B)中是否存在匹配。如果匹配,我将整行写入文本文件。我这样做的方式非常传统,单个文件需要花费大量时间,而我有数百个,大小不超过1GB

感谢您的时间

2 个答案:

答案 0 :(得分:4)

执行此操作的标准方法是实施Aho-Corasick algorithm。它会一次读取文件并查找所有出现的字符串。有关提供实现的文章和一些示例,请参阅https://www.informit.com/guides/content.aspx?g=dotnet&seqNum=869

更多信息后更新

假设文件A中的数字列表小到足以容纳在内存中,这就是你要做的事情,使用上面链接文章中的实现:

// Construct the automaton
AhoCorasickStringSearcher matcher = new AhoCorasickStringSearcher();
foreach (var searchWord in File.ReadLines(File_a)
{
    matcher.AddItem(searchWord);
}
matcher.CreateFailureFunction();

// And then do the search on each file
foreach (var fileName in listOfFiles)
{
    foreach (var line in File.ReadLines(filename))
    {
        var matches = matcher.Search(line);
        foreach (m in matches)
        {
            // output match
        }
    }
}

请注意,它只会对每个文件进行一次传递,并且永远不必在任何时候将多行文件加载到内存中。这里的限制因素是构建自动机所需的内存。

我用它来搜索总计超过100千兆字节的文件,大约有1500万个不同的字符串。构建自动机需要几分钟,但随后搜索速度非常快。该算法的一个非常好的属性是其复杂度为O(n + m),其中n是输入文件的大小,m是匹配项的数量。它搜索的字符串数量无关紧要。它可以搜索一百万个不同的字符串,就像搜索一两个字符串一样快。

100千兆字节将带你...大约40分钟阅读的东西。如果需要一个小时的时间才能在100千兆字节的数据中找到所有出现的1500万个不同字符串,我会感到非常惊讶。

匹配整个单词

另一个选择,如果你正在搜索整个单词,那就是抛弃Aho-Corasick算法。相反,请将您要查找的所有数字加载到HashSet<string>。然后读取每一行并使用正则表达式查找行中的所有数字,并检查它们是否存在于哈希集中。例如:

Regex re = new Regex("\w+");
foreach (var line in File.ReadLines(filename))
{
    var matches = re.Matchs(line);
    foreach (var m in matches)
    {
        if (hashSetOfValues.Contains(m))
        {
            // output match
        }
    }
}

这可能比Aho-Corasick算法慢一些,但它仍然只能通过数据传递一次。当然,这假定您有足够的内存来保存哈希集中的所有这些数字。

正如我在评论中提到的那样,整个单词还有其他选择。

另一个选项,如果你知道你要找的单词总是用空格分隔,那就是在你添加到自动机的单词的开头和结尾添加空格。或者,通过对实现本身的一些修改,您可以强制匹配器的Search方法仅返回整个单词中出现的匹配。这可以更容易地处理行的开头和结尾的匹配,以及其他非单词字符。

答案 1 :(得分:0)

foreach (string  _row in System.IO.File.ReadAllLines(AddressFilePath))
{
  if(_row.Contains(TextToSearch)){
     //Do something
     Console.WriteLine(_row);
  }
}