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

アイデアは、チャンクサイズだけ前にジャンプしてから、必要に応じて前のスペースに戻って作業することです。

このコードは、チャンクサイズよりも大きい単語が1つもないことを前提としていることに注意してください。また、複数のスペースの途中で分割されます。したがって、「... 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の方が読みやすいということに同意しますが、あまり明確ではありません。私はint、byte、またはlongですか?currentStringは文字列ですか、それともStringBuilderですか?もちろん、コードがプロジェクトにある場合は「定義に移動」することもできますが、Webサイトに投稿する場合、これはオプションではありません。また、変数がその定義以外の場所で初期化された場合はどうなりますか?ここで、ポスターが何を言おうとしているのかを判断するために初期化される場所を探すか、新しいVSプロジェクトを作成して、コードサンプルが機能するのにそれほど時間がかからないことを期待する必要があります。その結果、「レビューしたいコードを投稿するときは、タイプがわかっている場合はvarを使用しないようにしてください」と述べました。おそらくそれを述べるための最も正確な方法ではありませんが、迅速かつ簡単です。

@Alexあなたはあなたの意見を受け入れる権利があります。私の経験では、読む能力に関しては、それはあなたが慣れ親しんでいるものです。常にvarを使用する場合、タイプを知りたい場合は常に左を向いています(そして、何を作成したかを覚えておらず、ツールチップを待ちたくない場合)。もちろん、私はあなたのステートメントを例外とします。「コードをクリーンアップするのに役立ちます。変数に適切な名前を付ければ、varは読みやすさをまったく制限しないはずです。」これは対流のコーディングに反するだけではありません(「変数のタイプを指定するために変数名に依存しないでください。正しくない可能性があります。」)、単語(両側にスペースがある文字列)を見つけているように聞こえるので、nextWordに明確に名前を付けていません。例でのvarの使用(すべての使用)は、実際には読みやすさをまったく向上させません。変数の型を知りたいと思っているvarの使用に慣れているほとんどの人は、本能的にそれが設定された場所を見つけてそこから型を推測しようとしますが、varを使用しない人は本能的に変数定義に移動して型を決定します。さらに、特にメソッドから初期化する場合は、初期化によってすべての型を正確に推測できるわけではありません。

「多くの場合、varの使用はオプションであり、構文上の便宜のためです。ただし、変数が匿名型で初期化される場合、オブジェクトのプロパティにアクセスする必要がある場合は、変数をvarとして宣言する必要があります。後で。」 また、「このキーワードを使用する目的は、変数のタイプがわからない場合です。」

もう1つのリンク

于 2012-04-19T17:39:15.370 に答える