如何改进拆分 每 n 个字符而不是切断单词

本文关键字:单词 字符 拆分 何改进 | 更新日期: 2023-09-27 18:31:45

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

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;
                }
            }
        }

如何改进拆分 每 n 个字符而不是切断单词

有一个更简单的方法。类似的东西。

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;
}

这个想法是,你按块大小向前跳,然后在必要时向后工作到前一个空间。

请注意,此代码假定您不会有一个大于区块大小的单词。它还将在多个空间的中间分裂。因此,如果您有"...你好世界",你可能会得到一个以"你好"结尾的块。

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

    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 可以更容易阅读,但它也不太明确。 我是整数、字节还是长整型? currentString 是字符串还是 StringBuilder? 当然,如果代码在项目中,我们可以"转到定义",但是当发布在网站上时,这不是一个选项。 另外,如果变量在其他地方初始化,而不是其定义怎么办? 现在我必须去寻找初始化的位置,以确定海报想要表达的内容,或者创建一个新的 VS 项目,并希望他们的代码示例不会花费太长时间。 因此,我说"在发布你想要审查的代码时,如果你知道类型,尽量不要使用 var。 也许不是最准确的陈述方式,但快速而简单。

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

重要的是要注意"在许多情况下,var 的使用是可选的,只是一种语法上的便利。但是,当变量使用匿名类型初始化时,如果需要稍后访问对象的属性,则必须将该变量声明为 var。 以及"使用此关键字的目的是当您不知道变量类型时"。

再来一个链接