6

「不可能な」K&R演習。

「同じ間隔を実現するために、空白の文字列を最小数のタブと空白に置き換えるプログラムentabを作成します。同じタブストップを使用します。たとえば、n列ごとに使用します。nは変数または記号パラメーターのどちらにする必要がありますか?」

私が抱えている問題は、これを正しく行う方法がわからないことです。あまり説明的ではないことは知っていますが、それがここでの問題です。私が見た例のほとんどは、空白の数を数え、それらのシリーズをタブに置き換えましたが、これはその質問ではありません。私はその質問を理解していると思いますが、現在はこれを行うことができないと感じています。

誰か助けてもらえますか:)

編集:私がこれまでに書いたコードはここにあります

4

8 に答える 8

15

あなたの質問が「これは私に何を求めているのですか?」元の質問を言い換えることで役立つと思います(同じ質問を別の方法で提起します)。

スペースを含むテキストを入力として受け取り、可能な限りタブを使用して視覚的に同等のテキストを出力として生成するプログラムを作成します。

たとえば、8 文字ごとにタブストップを配置し、スペースを「.」として表示します。タブは「-」として。

input;
".foo:...bar;......#comment"
output;
".foo:-bar;-..#comment"

input;
".......-foo:.....bar;......#comment"
output;
"-foo:-.bar;-...#comment"

タブストップ パラメータ n を変更できるように、つまり 8 以外の n の値を許可するようにプログラムを作成します。

編集私はあなたのコードを見ましたが、必要以上に複雑だと思います。私のアドバイスは、一度に1文字ずつ行うことです。行全体をバッファリングする必要はありません。各文字を読み取るときに列数を維持します ('\n' はゼロにリセットし、'\t' はそれを 1 以上増やし、他の文字はそれを増やします)。スペース (またはタブ) が表示されたら、すぐには何も出力せず、タブ挿入プロセスを開始し、0 個以上のタブを出力してからスペースを出力します (「\n」または空白以外の文字のどちらか先に来る方)。

最後のヒントは、ステート マシンを使用すると、この種のアルゴリズムの記述、検証、テスト、および読み取りがはるかに簡単になるということです。

編集2 OPに私の答えを受け入れてもらうための恥知らずな試みで、上で提供したヒントとディスカッションでのコメントに基づいて、先に進み、実際に自分でソリューションをコーディングしました。

// K&R Exercise 1-21, entab program, for Stackoverflow.com
#include <stdio.h>
#define N 4     // Tabstop value. Todo, make this a variable, allow
                //  user to modify it using command line

int main()
{
    int col=0, base_col=0, entab=0;

    // Loop replacing spaces with tabs to the maximum extent
    int c=getchar();
    while( c != EOF )
    {

        // Normal state
        if( !entab )
        {

            // If whitespace goto entab state
            if( c==' ' || c=='\t' )
            {
                entab = 1;
                base_col = col;
            }

            // Else emit character
            else
                putchar(c);
        }

        // Entab state
        else
        {

            // Trim trailing whitespace
            if( c == '\n' )
            {
                entab = 0;
                putchar( '\n' );
            }

            // If not whitespace, exit entab state
            else if( c!=' ' && c!='\t' )
            {
                entab = 0;

                // Emit tabs to get close to current column position
                //  eg base_col=1, N=4, col=10
                //  base_col + 3 = 4 (1st time thru loop)
                //  base_col + 4 = 8 (2nd time thru loop)
                while( (base_col + (N-base_col%N)) <= col )
                {
                    base_col += (N-base_col%N);
                    putchar( '\t' );
                }

                // Emit spaces to close onto current column position
                // eg base_col=1, N=4, col=10
                //  base_col -> 8, and two tabs emitted above
                //  base_col + 1 = 9 (1st time thru this loop)
                //  base_col + 1 = 10 (2nd time thru this loop)
                while( (base_col + 1) <= col )
                {
                    base_col++;
                    putchar( ' ' );
                }

                // Emit buffered character after tabs and spaces
                putchar( c );
            }
        }

        // Update current column position for either state
        if( c == '\t' )
            col += (N - col%N); // eg col=1, N=4, col+=3
        else if( c == '\n' )
            col=0;
        else
            col++;

        // End loop
        c = getchar();
    }
    return 0;
}
于 2010-06-11T04:40:49.870 に答える
1

私はあなたの評価に同意します。n 個の空白をすべてタブに置き換えるだけでは十分ではありません。たとえば、n == 4 の場合、"hi blank blank blank blank" は "hi tab" ではなく、"hi tab blank blank" に置き換えます。

各行を読んでいるときに現在の位置を追跡し、この情報を使用して必要なタブの数を決定する必要があるようです。これは役に立ちますか?詳細が必要な場合はお知らせください。

「変数とシンボリック パラメータ」の部分については、どちらでも間違いなく実行可能ですが、変数を使用することの大きな利点が 1 つあります。それは、再コンパイルせずに n のさまざまな値に対してプログラムを実行できることです。

于 2010-06-11T04:35:21.183 に答える
0

私の理解では、この質問に答えるために、問題が何であるか、またはそれを解決する方法を実際に知る必要はありません。質問は、「シンボリックパラメータ」の代わりに変数をいつ使用するかを理解しているかどうかを尋ねているようです。「シンボリックパラメータ」が何を意味するのか、実際にはわかりません。それは時代遅れの命名法のようです。

そうは言っても、質問の最初の部分(スペースをタブに置き換える)を解決するのはかなり簡単です。除算と余りを考えてください。

于 2010-06-11T03:46:42.953 に答える
0

私はあなたのコードをざっと見てみましたが、あからさまに間違っていることは何もありません。

したがって、私のアドバイスは、デバッガーでいくつかの入力例を 1 ステップ実行して変数値を調べていくか、デバッグ用の print ステートメントを大量に追加することです。どちらの場合も、目標は、プログラムの状態が期待または意図したものから逸脱し始めるポイントを見つけることです。

于 2010-06-11T04:26:41.377 に答える
0

私は現在KnRを耕していて、このページに出くわしました:

練習問題の答え

エクササイズは次の場所にあります。

うまくいけば、これが役に立つと思います。

よろしくお願いします。

1 : http://users.powernet.co.uk/eton/kandr2/index.html「C プログラミング言語」、第 2 版、Kernighan と Ritchie - 演習への回答

于 2010-09-04T22:20:50.467 に答える
0

さらに簡潔な解決策がありますが、利用可能なコードのベスト プラクティス (短絡評価の悪用、継続によるぎこちない制御フロー、やや奇妙な「スペース」ループ) を採用していません。

#include <stdio.h>

#define TS 8

int main(int arg, char *argv[]) {
    int counter = 0, space_counter = 0, c;
    while ((c = getchar()) != EOF) {
        ++counter;
        if (c == ' ' && ++space_counter && (counter % TS) == 0) {
            space_counter = 0;
            c = '\t';
        } else if (c == '\t') {
            counter = space_counter = 0;
        } else if (c != ' ') {
            while (space_counter--)
                putchar(' ');
            space_counter = 0;
            if (c == '\n')
                counter = 0;
        } else {
            continue; /* don't call putchar(c) */
        }
        putchar(c);
    }
    return 0;
}

空白を除いて、読み取られたすべての文字がそのまま出力されます。代わりに空白がカウントされます。プログラムが空白以外の文字に遭遇した場合、以前に数えた数の空白を出力し、後でそのカウンターをリセットします。空白が検出された場合、カーソルがタブストップにあるかどうかを 2 番目のカウンター (行頭/最後のタブストップ以降の印刷文字) でチェックします。そうである場合、タブが印刷されます。それ以外の場合は、空白がカウントされます。

入力のタブは、スペース カウンターのリセットとタブの出力で処理され、その過程で余分な空白が排除されます。

于 2016-11-13T03:29:56.430 に答える
0

上記の最高評価の回答では、プログラムが非常に複雑です。答えのその部分を単純化するために、K&R のスタイルで記述された (主に ++ でインラインをインクリメントすることにより) より単純なコードを添付しました。

含む

タブ 4 を定義する

intメイン(){

char newsentence[255],c;
int spacecount = 0, oldsentencepointer = 0, newsentencepointer = 0;

printf("Give me a sentence please:\n");

while ((c = getchar()) != '\n') {
    if ((oldsentencepointer != 0) && (oldsentencepointer % TAB == 0) && (spacecount > 0))
       {
        newsentencepointer -= spacecount;         //if at tabstop, and spaces and not
                                                    first, go back to 1st space, set tab.
        newsentence[newsentencepointer++] = '\t';
        spacecount = 0;
        }

    if (c == ' ') {
        newsentence[newsentencepointer++] = ' ';
        spacecount++;                       //keep track of spaces before tab stop
    }

    else if (c == '\t') {
        newsentence[newsentencepointer++] = '\t' ;
        oldsentencepointer = TAB;   //set old pointer to TAB (does not matter if actual,
                                      only cadence important)
        continue;                   //continue from here so as not to increment 
                                      old sentence counter.
        }

    else {
        newsentence[newsentencepointer++] = c ;   //write whatever was old into new.
        spacecount = 0;                           //reset space counter.
        }

    oldsentencepointer++;

}

newsentence[newsentencepointer] = '\0';    //cap it off.

puts(newsentence);

return 0;

}

于 2014-11-11T13:42:51.583 に答える