C编程(K&R 1-22)折叠输入问题

Ric*_*and 2 c arrays

我是Delphi,Ruby和Javascript程序员,最终学习C - 从K&R开始.我正在尽力不要跳过并使用尚未介绍的库和概念.由于这是第一章教程,我只坚持一些语言功能,并希望保持这种方式.

1-22对于陌生人:

在第n列输入之前出现的最后一个非空白字符之后,编写一个程序将"长"输入行"折叠"成两条或更多条较短的行.

确保您的程序在非常长的行中执行智能操作,并且如果指定列之前没有空格或制表符.

在没有寻求外界帮助的情况下,我已经达到了1-22,但我一直在与1-22的"大多数"工作版本进行斗争.我认为我的算法......经常发臭.

到目前为止,我已经决定将输入折叠为40个字符.使用整数除法(/和模数%)我弄清楚我需要折叠每一行的次数,跳转到该列并向后计数直到我击中一个空格.空格被'\n'取代.重复+40个字符.

如果没有遇到空格,我们将在每个列停靠处进行硬折叠.

我得到一些偷偷摸摸的线路通过我的边界,并想知道我是否应该将输入读入char行[],然后一次复制到缓冲区40个字符,折叠缓冲区,并将缓冲区复制回行[] ..但这似乎特别没有工作 string.h

代码在下面,我正在寻找正确方向和解决方案的提示,因为我认为我几乎就在那里.

#include <stdio.h>

#define MAXBUF 1000
#define WRAP 20

int getline(char s[],int lim);

int main(void)
{
    int len;                /* length of each input */
    int folds;              /* how many folds we've performed */
    int lines;              /* lines the input breaks down to given len */
    int index;              /* index of fold */
    int didfold;            /* true (1) if we were able to fold on a ' ' */
    int i;                  /* loop counter */
    char line[MAXBUF+1];    /* input line */
    char buf[MAXBUF+1];     /* temp buffer for copying */

    while ((len=getline(line,MAXBUF)) > 0)
    {
        /* how many times should we fold the input
           account for left overs
        */
        lines = len / WRAP;
        if (len % WRAP != 0)
            ++lines;
        /* init */
        folds = 1;

        while (lines>0)
        {
            didfold = 0;
            for (index=(WRAP*folds)-1;index>0 && !didfold;--index)
            {
                if (line[index] == ' ')
                {
                    line[index] = '\n';
                    didfold = 1;
                    --lines;
                    ++folds;
                }
            }
            // if (!didfold)
            // {
            //  i = 0;
            //  while ((buf[i] = line[i]) != '\0');
            //      ++i;
            //  for(index=i=0;buf[i]!='\0';++index,++i)
            //  {
            //      line[index] = buf[i];
            //      if (index==(WRAP*folds)) 
            //      {
            //          ++i;
            //          line[i] = '\n';
            //          didfold = 1;
            //          ++folds;
            //          linelength -= WRAP * folds;
            //      }
            //  }
            // }

        }
        printf("--------------------|||||\n");
        printf("%s",line);
    }
    return 0;
}


int getline(char s[],int lim)
{
    int i,c;

    for (i=0;i<=lim && ((c = getchar()) != EOF) && c != '\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = '\n';
        ++i;
    }
    s[i] = '\0';

    return i;
}
Run Code Online (Sandbox Code Playgroud)

我有另一个版本可以将自己编入索引column - 40并向前推进更多问题.

UPDATE

以下是我正在解决的错误所以我不是通过远射来完成但是......

我是朝着正确的方向前进的吗?我想确保掌握经典的UNIX文本过滤器.到目前为止,这段代码感觉更好,但仍然是hack'ish - 我只是觉得我没有抓住一个关键概念,但需要用漂亮的代码来完成它.

/* Exercise 1-22. Write a program to ``fold'' long input lines into two or more shorter
   lines after the last non-blank character that occurs before the n-th column of input.

   Make sure your program does something intelligent with very long lines, and if there
   are no blanks or tabs before the specified column. */

#include <stdio.h>

#define WRAP 20

int main(void)
{
    char buf[WRAP+1];
    int bufpos = 0;
    int last_whitespace = -1;

    for(bufpos=0;bufpos<(WRAP-1);++bufpos) {
        putchar('-');
    }
    putchar('|');
    putchar('\n');
    bufpos=0;

    while ((buf[bufpos]=getchar())!=EOF) {
        // if at buffer or newline
        if (bufpos==(WRAP-1) || buf[bufpos] == '\n' || buf[bufpos] == '\t') {
            ++bufpos;
            buf[bufpos] = '\0';

            if (buf[bufpos]==' ' || buf[bufpos] == '\n') {
                // whitespace, flush buf and go.
                printf("%s",buf);
            } else {
                if (last_whitespace>0) {
                    buf[last_whitespace] = '\n';
                    printf("%s",buf);
                } else {
                    //hard fold!
                    printf("%s",buf);
                    putchar('\n');
                }
            }           
            for (bufpos=0;bufpos<WRAP;++bufpos)
                buf[bufpos] = '\0';
            bufpos=0;
            last_whitespace=-1;
        } else {
            if (buf[bufpos]==' ')
                last_whitespace = bufpos;
            ++bufpos;   
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

hob*_*bbs 6

逐行读取每一行,并保持一些指针(或者,如果你还没有使用指针,则为偏移量).一个用于"行的开头",它将开始指向行的开头,一个用于您看到的最后一个空格,它将从NULL开始(如果您使用偏移,-1将代替),和一个当前的阅读位置.

然后,每当你到达一些空格时,你应该检查是否可以输出从前一个空格到(但不包括)当前空格的所有内容而不超出WRAP字符.如果可以,则立即输出,并更新前一个空格指针以指向当前的空格.如果不能,则输出换行而不是前一个空格,并更新行首指针和最后一个空白指针.

现在唯一剩下的就是"处理真正的长线",你可以通过查看线的起点和看到的最后一个空格是否在同一个地方来做,但我们仍然超出了WRAP列 - 这意味着我们有一个单词不适合一行.在这种情况下,我们应该在这里插入一个换行符,重置行首,然后继续.

确保在到达输入行末尾时还打印尚未打印的任何内容,并输出最终换行符.

这个算法的优点在于它实际上并不需要一个行数组来工作 - 因为它逐个字符地处理它可以使用很少的更改一次读取输入文件一个字符,给定一个缓冲区至少是WRAP人物.