搜索字符串C#中每个子字符串的出现次数

时间:2014-04-30 15:37:07

标签: c# regex string performance

我知道这里已经讨论了类似的问题和问题,但不完全是我需要的问题。

让我们面对这个问题,我们有一根长绳子,一根很长的绳子,大海捞针,还有一根针。经典问题:搜索出现的所有内容。好Regex.Matches是一个很好的函数,它只有一个问题,在我们的例子中是一个严重的问题,它不计算重叠的字符串。

例如

string haystack = "(anything)....bbb....(anything)";  
string needle = "bb"; //must be a string not a char

现在我们看到,bb在干草堆的bbb部分中是2倍。 (BBbbBBRegex.Matches只找到第一个,并从第三个b进一步搜索。并且不会找到任何其他。

任何想法如何在长草垛字符串中搜索具有重叠选项的毛发子串(当然必须有效)?

谢谢,如果重复,请抱歉。

4 个答案:

答案 0 :(得分:3)

在循环中使用string.IndexOf

string haystack = "(anything)....bbb....(anything)";  
string needle = "bb"; 
int pos = 0;
while((pos = haystack.IndexOf(needle, pos)) != -1)
{
    Console.Write("Found at pos:" + pos.ToString());
    Console.WriteLine(" - " + haystack.Substring(pos, needle.Length));
    pos++;
}

答案 1 :(得分:1)

为什么不只是维护指向子串的位置的指针,然后每当找到匹配时从该位置+ 1恢复你的Regex.Matches。

答案 2 :(得分:1)

更简单的解决方案是在其他人建议的循环中使用string.IndexOf,但是......如果你真的想使用正则表达式,你可以使用积极的先行来处理重叠。例如:

string test = "(anything)....bbb....(anything)";
Regex r = new Regex("b(?=b)");
foreach (Match m in r.Matches(test)) 
{
    Console.WriteLine(string.Format("match at: {0}",m.Index));
}

将在1415两个索引处匹配。

对于2个字符的匹配,这是可以管理的,但是如果匹配时间较长,可能会变得很痛苦。

确定这个在实践中是否比循环解决方案中的string.IndexOf更快

是留给读者的练习。

编辑:因为我的好奇心越来越好,我不得不试着找出哪一个实际上更快,这里有一些测试代码:

http://dotnetfiddle.net/qneK5u

        string test = "(anything)....bbbbbb....(anything)";
        Regex r = new Regex("b(?=b)");
        var s = new System.Diagnostics.Stopwatch();
        s.Start();
        int i=0; 
        int l=5000;
        for (;i<l;i++) {
            var result = r.Matches(test);
        }
        Console.WriteLine(s.ElapsedTicks.ToString());
        i = 0;
        string needle = "bb"; 
        int pos = 0;
        s.Reset();
        s.Start();
        for (;i<l;i++) {
            pos = 0;
            while((pos = test.IndexOf(needle, pos)) != -1)
            {
                pos++;
            }
        }
        Console.WriteLine(s.ElapsedTicks.ToString());

正则表达式解决方案的出现速度明显加快,但我不确定我是否正在进行公平的测试。

答案 3 :(得分:0)

此函数返回起始匹配针字符串的索引列表(可能比正则表达式更快):

    public static List<int>  GetPositions(string haystack , string needle)
    {
        List<int> ret = new List<int>();
        if (string.IsNullOrEmpty(haystack) || string.IsNullOrEmpty(needle))
            return ret;
        for(int i=0;i<haystack.Length-needle.Length+1;i++)
        {
            int j = 0;
            for(;j<needle.Length && haystack[i+j]==needle[j];j++);
            if(j==needle.Length )
                ret.Add(i);
        }
        return ret;
    }