0

我有我创建的代码来做到这一点,但是我的问题是有一种方法可以改进我的代码。似乎有更好的方法来解决这个问题。

public static IEnumerable<string> SplitEvery(this string str, int chunkSize, bool splitAtSpaces)
    {
        var chars = str.ToCharArray();

        var i = 0;
        var currentString = string.Empty;

        var nextWord = false;

        while (i < chars.Length)
        {
            if (nextWord)
            {
                currentString = string.Empty;
                nextWord = false;
            }

            if (currentString.Length < chunkSize)
            {
                currentString += chars[i];
                if ((i + 1) == chars.Length)
                    yield return currentString;
                i++;
            }
            else
            {
                if (splitAtSpaces)
                {
                    var charAtEnd = currentString[currentString.Length - 1];

                    if (charAtEnd == ' ' || chars[i] == ' ')
                    {
                        nextWord = true;
                        yield return currentString;
                    }
                    else
                    {
                        var lastSpace = currentString.LastIndexOf(' ');
                        i = lastSpace + 1;
                        nextWord = true;
                        yield return currentString.Substring(0, i);
                    }
                }
                else
                {
                    nextWord = true;
                    yield return currentString;
                }
            }
        }
4

2 回答 2

3

有一个更简单的方法。就像是。

int idx = 0;
while (idx < str.Length)
{
    int endIdx = idx + chunkSize;
    if (endIdx >= str.Length)
        endIdx = str.Length;
    else if (splitAtSpaces)
    {
        while (str[endIdx] != ' ')
            --endIdx;
    }
    yield return str.Substring(idx, endIdx - idx);
    idx = endIdx;
}

这个想法是,如果需要,您可以向前跳块大小,然后向后工作到前一个空间。

请注意,此代码假定您不会有一个大于块大小的单词。它也会在多个空间的中间分裂。所以如果你有“... hello world”,你可能会得到一个以“hello”结尾的块。

于 2012-04-19T17:41:24.980 回答
-3

以下应该适用于所有情况,并且比您建议的解决方案更快。

    public static IEnumerable<string> SplitEvery(this string str, int chunkSize, bool splitAtSpaces)
    {
        if (splitAtSpaces)
        {
            return SplitEvery_AtSpace(str, chunkSize);
        }
        else
        {
            return SplitEvery_IgnoreSpace(str, chunkSize);
        }
    }

    public static IEnumerable<string> SplitEvery_AtSpace(string str, int chunkSize)
    {
        int lastStartPoint = 0,
            nextStartPoint = chunkSize;
        List<string> output = new List<string>();

        for (int i = 0; i < str.Length && nextStartPoint < str.Length; i++)
        {
            while (nextStartPoint > lastStartPoint + 1 && str[nextStartPoint - 1] != ' ')
            {
                nextStartPoint--;
            }

            if (nextStartPoint == lastStartPoint)   //If no space in line break
            {
                output.Add(str.Substring(lastStartPoint, chunkSize));
                nextStartPoint += chunkSize;
            }
            else
            {
                output.Add(str.Substring(lastStartPoint, nextStartPoint - lastStartPoint - 1)); //-1 skips space
            }


            //Prep for next loop
            lastStartPoint = nextStartPoint;
            nextStartPoint += chunkSize;
        }

        if (lastStartPoint < str.Length) { output.Add(str.Substring(lastStartPoint)); } //Add leftover

        return output;  //May want to convert to array if it will be accessed often.
    }

    public static IEnumerable<string> SplitEvery_IgnoreSpace(string str, int chunkSize)
    {
        int lastInserted = 0;
        List<string> output = new List<string>();

        for (int i = 0; i < str.Length && (lastInserted + chunkSize) < str.Length; i++)
        {
            output.Add(str.Substring(lastInserted, chunkSize));

            //Prep for next loop
            lastInserted += chunkSize;
        }

        if (lastInserted < str.Length) { output.Add(str.Substring(lastInserted)); } //Add leftover

        return output;  //May want to convert to array if it will be accessed often.
    } 
  1. 在发布您要审查的代码时,如果您知道类型,请尽量不要使用 var。它使代码更难阅读和调试
  2. 在循环中连接到字符串通常是一个 主意。而是使用System.Text.StringBuilder

更新:@payo 和@Alex
我认为您错过了我的观点,但感谢您指出您投反对票的原因。请允许我澄清和回应。

对于内置关键字(如 int、string、bool)的局部变量,将它们声明为 var 是没有意义的,因为您不会保存很多击键。
当然 var 有一些很好的用途,例如,变量是匿名的,类型名称很长(比如GetResponseToSuggestForTodayTrimmedNoInputResults甚至ALongVarName),或者你不知道变量的实际类型。

@payo 在某些情况下,我同意 var 可以更容易阅读,但它也不太明确。i 是 int、byte 还是 long?currentString 是字符串还是 StringBuilder?当然,如果代码在项目中,我们可以“转到定义”,但是当发布在网站上时,这不是一个选项。此外,如果变量在其定义之外的其他地方初始化怎么办?现在我必须去寻找它的初始化位置以确定发布者想说什么,或者创建一个新的 VS 项目并希望他们的代码示例不会花费太长时间来工作。结果我说“在发布您想要审查的代码时,如果您知道类型,请尽量不要使用 var。” 也许不是最准确的表述方式,但又快又容易。

@Alex您有权发表自己的意见,以我的经验,就阅读能力而言,您所使用的更多。如果你总是使用 var ,那么如果你想知道类型,你总是会向左看(并且不记得你做了什么并且不想等待工具提示)。当然,我确实对您的陈述表示异议“它有助于清理您的代码,如果您正确命名变量,那么 var 根本不应该限制可读性。” 因为这不仅不利于编码对流(“不要依赖变量名来指定变量的类型。它可能不正确。”),您没有明确命名 nextWord,因为听起来您正在寻找单词(两边都有空格的字符串)。您在示例中使用 var (所有用途)实际上并没有增加可读性。大多数习惯使用 var 并想知道变量类型的人会本能地找到它的设置位置并尝试从中猜测类型,而不使用 var 的人会本能地转到变量定义来确定类型。此外,并非所有类型都可以通过初始化准确推断,尤其是从方法初始化时。

重要的是要注意“在许多情况下,使用 var 是可选的,只是为了语法方便。但是,当使用匿名类型初始化变量时,如果需要访问对象的属性,则必须将变量声明为 var稍后。” 还有“使用这个关键字的目的是当你不知道变量的类型时。”

还有一个链接

于 2012-04-19T17:39:15.370 回答