快速自定义字符串拆分

时间:2012-12-10 22:49:09

标签: c# .net string

我正在编写自定义字符串拆分。它将分成一个点(.),前面没有奇数个反斜杠(\)。

«string» -> «IEnemerable<string>»
"hello.world" -> "hello", "world"
"abc\.123" -> "abc\.123"
"aoeui\\.dhtns" -> "aoeui\\","dhtns"

我想知道是否存在将重用原始字符串的子字符串(用于速度),或者是否存在可以快速执行此操作的现有拆分?


这就是我所拥有的,但是比input.Split('.') //慢2-3倍,其中input是一个字符串。 (我知道这是一个(稍微复杂的问题,但不是那么多)

    public IEnumerable<string> HandMadeSplit(string input)
    {
        var Result = new LinkedList<string>();
        var word = new StringBuilder();
        foreach (var ch in input)
        {
            if (ch == '.')
            {
                Result.AddLast(word.ToString());
                word.Length = 0;
            }
            else
            {
                word.Append(ch);
            }
        }
        Result.AddLast(word.ToString());
        return Result;
    }

它现在使用List而不是LinkedList,并记录子字符串的开头和结尾,并使用string.substring创建新的子字符串。这做了很多,几乎和string.split一样快,但我添加了我的调整。 (将添加代码)

3 个答案:

答案 0 :(得分:3)

如果您需要表现,您展示的循环是正确的方法。 (正则表达式不会)。

切换到基于索引的for循环。记住比赛开始的索引。不要附加个人字符。相反,请记住要复制的字符范围,并通过每个项目Substring调用来执行此操作。

另外,请勿使用LinkedList。除了随机访问突变之外,几乎所有情况都比List慢。

您也可以从List切换到使用Array.Resize调整大小的普通数组。这会导致稍微繁琐的代码(因为您已将List类的一部分内联到您的方法中),但它会减少一些小的开销。

接下来,不要返回IEnumerable,因为在访问其项目时会强制调用者通过间接方式。返回List或数组。

答案 1 :(得分:3)

这是我最终确定的那个。它不像string.split那么快,但足够好并且可以修改,以做我想要的。

    private IEnumerable<string> HandMadeSplit2b(string input)
    {
        //this one is margenaly better that the second best 2, but makes the resolver (its client much faster), nealy as fast as original.
        var Result = new List<string>();
        var begining = 0;
        var len = input.Length;
        for (var index=0;index<len;index++)
        {
            if (input[index] == '.')
            {
                Result.Add(input.Substring(begining,index-begining));
                begining = index+1;
            }
        }
        Result.Add(input.Substring(begining));
        return Result;
    }

答案 2 :(得分:2)

您不应该尝试使用string.Split

如果您需要帮助来实现它,解决此问题的一种简单方法是使用循环扫描字符串,跟踪找到符合条件的点的最后位置。当您找到新的限定点(或到达输入字符串的末尾)时,只需yield return当前子字符串。

编辑:关于返回列表或数组与使用yield

如果在您的应用程序中,最重要的是调用者在迭代子字符串上花费的时间,那么您应该填充列表或数组并返回它,如接受的问题中所建议的那样。在收集子串时我不会使用可调整大小的数组,因为这会很慢。

另一方面,如果您关心整体性能和内存,并且有时调用者不必遍历整个列表,则应使用yield return。当您使用yield return时,您的优势在于,在调用者调用MoveNext(直接或间接通过foreach)之前,根本不会执行任何代码。这意味着您可以保存用于分配阵列/列表的内存,并节省分配/调整大小/填充列表所花费的时间。你将花费时间几乎只是在寻找子串的逻辑上,这将是懒惰的,即 - 只有当实际需要时,因为调用者继续迭代子串。