Проблема сложного ввода в C-программировании (K & R 1-22) - PullRequest
2 голосов
/ 08 марта 2011

Я программист на Delphi, Ruby и Javascript, который наконец изучает C - начиная с K & R.Я стараюсь изо всех сил не прыгать вперед и использовать библиотеки и концепции, которые еще не представлены.Так как это урок первой главы, я придерживаюсь только нескольких языковых особенностей и хотел бы сохранить его таким.

1-22 для незнакомых:

Написатьзапрограммировать `` сложить '' длинные строки ввода в две или более короткие строки после последнего непустого символа, который находится перед n-м столбцом ввода.

Убедитесь, что ваша программа делает что-то умное с очень длинными строками, и если перед указанным столбцом нет пробелов или табуляций.

Я сделал это в 1-22 безищу помощь извне, но я боролся с «в основном» рабочими версиями 1-22.Я думаю, что мой алгоритмический ... ошибочный выбор воняет.

До сих пор я решил сложить ввод в 40 символов.Используя целочисленное деление (/ и модуль%), я выясняю, сколько раз мне нужно сложить каждую строку, перейти к этому столбцу и вести обратный отсчет, пока не попаду в пробел.Пробел заменяется на \ n.Повторите +40 символов.

Если не будет пробелов, мы будем пихаться в сложную складку на каждой остановке столбца.

Я получаю некоторые строки, пробирающиеся через мою границу, и задаюсь вопросом, могу ли яВместо этого не следует читать входные данные в символьную строку [], а затем копировать в буфер 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;
}

У меня есть другая версия, которая индексирует себя дляcolumn - 40 и рассчитывает вперед с еще большим количеством проблем.

ОБНОВЛЕНИЕ

В следующем есть ошибки, с которыми я работаю, так что я не сделал длинного выстрела, но..

Я направляюсь в правильном направлении?Я хочу убедиться, что я понимаю классический текстовый фильтр UNIX.Пока что этот код выглядит лучше, но все еще хакерский - я просто не чувствую, что я понимаю ключевую концепцию, но мне нужно было закончить это с хорошим кодом ..

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

Ответы [ 3 ]

6 голосов
/ 08 марта 2011

Прочитайте каждую строку, посимвольно, и поддерживайте несколько указателей (или, если вы еще не используете указатели, смещения).Один для «начала строки», который будет начинаться с указания на начало строки, один для последнего пропущенного пробела, который будет начинаться с NULL (если вы используете смещения, вместо этого будет использоваться -1),и один для текущей позиции чтения.

Затем, всякий раз, когда вы достигаете некоторого пробела, вы должны проверить, можете ли вы вывести все из предыдущего пробела до (но не включая) текущего пробела, не выходя за пределы WRAP символов.Если вы можете, то сразу же выведите его и обновите предыдущий указатель пробела, чтобы он указывал на текущий пробел.Если вы не можете, тогда выведите новую строку вместо предыдущего пробела и обновите указатель начала строки, а также указатель последнего пробела.

Теперь единственное, что осталось сделать, - это действительно обработатьдлинные строки ", что можно сделать, посмотрев, находятся ли начало строки и последний увиденный пробел в одном и том же месте, но мы все еще за пределами WRAP столбцов - это означает, что мы имеемслово, которое не помещается на одной строке.В этом случае нам, вероятно, следует вставить разрыв строки прямо здесь, сбросить начало строки и продолжить работу.

Убедитесь, что вы также печатаете все, что еще не было напечатано, когда достигнете концастроки ввода, а также вывод последней строки.

Хорошая особенность этого алгоритма в том, что ему фактически не нужен массив строк для работы - поскольку он обрабатывает символ за символом, он можетработать с очень небольшими изменениями, читая входной файл по одному символу за раз, учитывая буфер не менее WRAP символов.

1 голос
/ 08 марта 2011

Мысль о том, почему некоторые строки проходят мимо вашей границы: когда вы переходите к index = (WRAP * folds) -1, это изначально ставит вас на 19 - вы затем начинаете считать в обратном направлении до пробела.Допустим, это пробел в индексе 17. Вставьте новую строку.Затем вы увеличиваете 'folds' и пересчитываете (index = (WRAP * folds) -1), что теперь равно 39. Допустим, index 39 - это пробел, поэтому вы сразу вставляете новую строку.Строка между двумя введенными вами строками длиной более 20 символов!

Вместо этого я бы порекомендовал инициализировать индекс WRAP-1 непосредственно перед циклом for, а затем увеличивать индекс на WRAP каждый раз, когда вы перезапускаете цикл (после создания каждой новой строки).Это предотвратило бы, что следующая отправная точка для проверки и вставки каждой новой строки будет больше, чем пробелы WRAP за пределами того места, где закончилась последняя.*

0 голосов
/ 08 марта 2011

Я думаю, изначально, когда вы вычисляете длину вашей строки в методе getline (), просто считайте до EOF без учета пробелов. Теперь, когда вы находитесь в своем основном методе, теперь учитывайте пробелы и другие вещи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...