C-Программирование (K&R 1-22) сложите входную задачу



Я программист 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]) != '');
            //      ++i;
            //  for(index=i=0;buf[i]!='';++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] = '';

    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] = '';

            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] = '';
            bufpos=0;
            last_whitespace=-1;
        } else {
            if (buf[bufpos]==' ')
                last_whitespace = bufpos;
            ++bufpos;   
        }
    }
    return 0;
}
190   3  

3 ответов:

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

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

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

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

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

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

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

index = WRAP-1;
while (lines > 0) { 
    for (didfold=0; index>0 && !didfold; --index)
    {
        if (line[index] == ' ')
        {
            line[index] = '\n'
            didfold = 1;
            --lines;
            index = index+WRAP;
        }
    }
}

Я надеюсь, что это донесет идею до всех...

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

    Ничего не найдено.

Добавить ответ:
Отменить.