0

これはCの割り当てです。私は誰かに私のためにこれをするように頼んでいません、私はただ壁にぶつかっただけです。明日ですが、どうすればいいのかわかりません。私は初心者で、頭が痛くなり始めています

与えられた数の列にうまく収まるようにテキストをフォーマットするANSICプログラムを作成します。テキストフォーマッタは、入力テキストファイルを右揃えにして、1つの例外を除いて、右マージンが一直線に並ぶようにする必要があります。最後の行は正しく正当化されていません。また、段落は一緒にマージされません。出力ライン間のスペースは等間隔である必要があります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define IN 1
#define OUT 0

/*
   This is the start of the main pgoram which originated from the K & R word  counter...
   we comment to understand each part...
 */
int main()
{
    /*
     * This is the pointer to the file object we will be readin in
     * from...
     */
    FILE           *ptr_file;
    char           *outputbuf;

    /*
     * This variable will hold the maximum width of the line we are to
     * output
     */
    int width;
    char eatspace;
    char  c;    /* We read each character invidually */

    int   state = OUT;

    int   nc = 0;   /* This is the total count of all words in the document */
    int   nl = 0;   /* This is the total count of newlines in the document  */
    int   nw = 0;  
    int   lw = 0;   /* Count the total whitespaces spaces per line */
    int   buff_offset = 0; /* Keep track of how many letters we are into the current output line */

    /* Opens a file stream for the .txt file to be read in */
    ptr_file = fopen("hollo_man.txt", "r");
    if ((fopen("hollo_man.txt", "r")) != NULL) {
        /*
         * This loop reads in one character at a time until the end
         * of file
         */

        /* Read the first line to get the width of the output */
        fscanf (ptr_file, "%i", &width); 
        outputbuf = (char*) malloc(width + 1);
        //fscanf(ptr_file, "%c", &eatspace);

        int prev_char_was_space = 0;

        while ((c = fgetc(ptr_file)) != EOF)
        {
            ++nc;
            if (c == '\n' || strlen(outputbuf) == width) 
            {
                outputbuf[buff_offset] = '\0';      
                ++nl;
                //              printf("Saw a newline, newline count is now: %i\n", nl);
                /* Our buffer needs to be ended since we saw a newline */

                for(int i = 0; i < (width - buff_offset); i++)
                {
                    printf(" ");

                }
                printf("%s\n", outputbuf);

                memset(outputbuf, width, '\0');

                buff_offset = 0; 
                prev_char_was_space = 0;

            }

            /* This more verbose check is to see if there is other whitespace */
            else if (isspace(c)) 
            {


                /* We only store one space between words in the output, this allows us to easily and evenly pad with white space later */
                if (!prev_char_was_space)
                {

                    outputbuf[buff_offset] = c;
                    outputbuf[buff_offset + 1] = '\0';                  
                    buff_offset++;                  

                    lw++;
                    prev_char_was_space = 1;
                }   
            }
            else /* This was not a whitespace character so store it in the current line buffer */
            {

                prev_char_was_space = 0; /* Keep track that we didnt have a whitespace for the next iteration */
                outputbuf[buff_offset] = c;
                buff_offset++;
                ++nw;


            }

        } /* End reading each character */

        /* This line should indeed print output to console for now */
        //fprintf(stderr, "ORIG LINE COUNT: %d\nORIG WORD COUNT: %d\nORIG CHAR COUNT: %d\n", nl, lw, nc);
        /* Close our file and clean up */
        fclose(ptr_file);
    }

    return 0;
}

空白行を印刷するだけです。別のバッファが必要だと思いますが、よくわかりません。それを印刷してから、単語をパディングされたスペースで等間隔に配置するにはどうすればよいですか?また、割り当てられた幅に各行を印刷する方法もわかりません。どんな助けでも大歓迎です!

4

2 に答える 2

2

まず、fopen("hollo_man.txt", "r")2回呼び出さないでください。で、ポインタを確認してくださいif

次に、ファイルを単語ごとに読む必要があります。

char words[1024];
char * next_word = words;
while(fscanf(ptr_file, "%s", next_word) {

それらの長さを数える

size_t word_length = strlen(next_word);
next_word += word_length + 1;

必要な幅に達したら、それらを印刷します。

total_length +=  word_length;
if (total_length > maxColumns) {
     size_t extra_spaces = total_length - word_length - 2;

これは役に立ちますか?

完全な解決策は次のとおりです。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void justify(FILE* in, FILE * out, int columns) {
    char words[1024];
    char * next_word = words;

    ssize_t total_length = 0;
    size_t num_words = 0;

    while (fscanf(in, "%s", next_word) == 1) {
        size_t word_length = strlen(next_word);
        next_word += word_length + 1;
        num_words++;
        total_length += word_length;

        if (total_length + num_words > columns) {

            size_t spaces_needed = columns - (total_length - word_length);

            int minspoaces = 1;
            if (num_words > 2) // avoids nasty floating point exception if no two words fit on a line
                minspoaces = spaces_needed / (num_words - 2);


            char * word_print = words;

            size_t chars_printed = fprintf(out, "%s",word_print);
            word_print += strlen(word_print) + 1;
            size_t spaces_printed = 0;
            ssize_t words_to_print = num_words - 2;

            fflush(out);

            while (words_to_print > 0) {
                int spaces_to_print = minspoaces;
                if (((spaces_needed - spaces_printed) % words_to_print) * 2 >= words_to_print) // spreads spaces out along the line
                    spaces_to_print++;
                spaces_printed += spaces_to_print;
                words_to_print--;
                chars_printed += fprintf(out, "%*c%s", spaces_to_print, ' ', word_print);
                word_print += strlen(word_print) + 1;
                fflush(out);
            }
            fprintf(out, "\n");

            memmove(words, word_print, (total_length = strlen(word_print)) + 1);
            num_words = 1;
            next_word = words + total_length + 1;
        }

    }

    char * word_print = words;
    while (word_print != next_word) {
        word_print += fprintf(out, "%s ", word_print);
    }

    fprintf(out, "\n");
}

int main(int argc, char ** argv) {

    int columns = atoi(argv[1]);

    FILE * in = stdin;

    if (argc >= 3 && argv[2]) {
        in = fopen(argv[2], "r");
        if (!in) {
            perror("fopen");
            return -1;
        }
    }

    justify(in, stdout, columns);

}
于 2013-02-06T17:42:54.060 に答える
2

ダブル fopen のマイナーな問題がありますが、これは 1 つに削減する必要があります。

ファイルはおそらく次のような形式になっています。

15
The quick
brown

問題は、ロジックが次のようなものであることです。

/* Opens a file stream for the .txt file to be read in */
ptr_file = fopen("hollo_man.txt", "r");
if (/*the file was opened correctly */) {

        Read 'width' from the first word of the file;
        Create a buffer exactly 'width'+1 in size;

        while(get_a_character != EOF) {
            increment_total_character_count;
            if(character_is_newline)
                increment_newline_count;
                insert a '\0' in the output buffer;
                reset the index we're inserting into the output buffer
                prevCharacterIsSpace = false;
            if(character_is_space)
                if(previous_character_NOT_a_space)
                    put_character_in_output_buffer;
                    increment_word_counter;
                    prevCharacterIsSpace = true;
            else
                prevCharacterIsSpace = true;
                put_character_in_output_buffer;
                increment_nw (never used)
        }


        needed_spaces = (width - nc) % lw;
        printf(" %s", outputbuf);

入力ファイルが上記の形式で、幅が独自の行に表示されている場合、読み取っている文字ストリームは次のようになります。

'15' (read as a unit with the %i)
'\n'
'T'
'h'
...
'w'
'n'
'\n'

文字読み取りループは、改行を最初の文字と見なします。出力バッファに null を挿入し、prevCharacterIsSpace を false に設定してから続行します。ファイル形式が上記のものと一致する場合は、「幅」を読み取った直後に「\n」を「食べる」ことでこれを修正することをお勧めします。

isspace関数は改行に対して true を返すため、改行が出力バッファーの次のスロットに入れられ、単語カウンターがインクリメントされることに注意してください (プログラムの最後にある printf のコメントを外した場合、その効果が見られるはずです) 。. 修正は、おそらく単にすることif (isspace(c))ですelse if (isspace(c))

もう 1 つの問題は、ファイルからそれぞれ別の行を同じバッファーにコピーしていることです。したがって、入力の最終行以上を表示する方法はありません。おそらく、印刷コードをif (c == '\n') {ブロック内に配置する必要があります。これにより、読みながら各行を印刷できます。

ここにあるコードは、右寄せされたテキストの印刷を処理していませんが、その簡単な解決策は小さなループです:

for (i = 0; i < (width - buff_offset); i++)
    printf(" ");

出力を印刷する直前に挿入されます。

于 2013-02-06T18:06:41.083 に答える