2

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

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

我想知道是否有一个子字符串可以重用原始字符串(为了速度),或者是否有一个现有的拆分可以快速做到这一点?


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

    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 一样快,但我已经添加了我的调整。(将添加代码)

4

3 回答 3

3

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

切换到基于索引的 for 循环。记住比赛开始的索引。不要附加单个字符。相反,请记住要复制的字符范围,然后对每个项目进行一次Substring调用。

另外,不要使用LinkedList. List除了随机访问突变之外,几乎所有情况下它都比 a 慢。

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

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

于 2012-12-11T09:49:41.033 回答
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;
    }
于 2012-12-11T20:58:30.440 回答
2

你不应该尝试使用string.Split它。

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

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

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

另一方面,如果您关心整体性能和内存,并且有时调用者不必遍历整个列表,您应该使用yield return. 使用 时,您的优势是在调用者调用(直接或间接通过 a )yield return之前根本不会执行任何代码。这意味着您节省了分配数组/列表的内存,并节省了分配/调整大小/填充列表所花费的时间。您将几乎只花时间在查找子字符串的逻辑上,这将是懒惰地完成的,也就是说 - 仅在实际需要时,因为调用者继续迭代子字符串。MoveNextforeach

于 2012-12-10T23:22:02.047 回答