Добавьте номера строк в начало каждой строки в файле, используя C - PullRequest
1 голос
/ 30 апреля 2019

Я работаю над заданием, которое читает текстовый файл и добавляет номер строки в начале каждой строки.

Я довольно новичок в кодировании, поэтому извините, если это простая задача,Код, который я написал, даст мне вывод, который подскажет мне, сколько строк в файле, но я не могу понять, как на самом деле сделать его нумерацией строк и показать их мне.

//lineNumber = 1;
//Open the file
//While ((c = read a character) is not EOF)
//    If (c is \n)
//        Print "lineNumber", then increment it
//    Print c
//End while
//Close the file
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main() {

    int ln = 1;
    char c;
    FILE *fp = fopen("text.txt", "r");

    while((c=getc(fp))!=EOF) {

        if (c=='\n'){
            ln++;
        }
    }
    printf("lines num: %d",c);
    fclose(fp);
    //return 0;
}

Пример ввода:

This is a text file
This text file has words in it.

Пример вывода:

000001 This is a text file
000002 This text file has words in it.

Ответы [ 4 ]

3 голосов
/ 30 апреля 2019

у вас есть программа, которая подсчитывает количество строк в файле, вам нужно изменить это так, чтобы вместо отображения счетчика в конце вам нужно было отображать содержимое файла

(например, используя putchar(c); после каждого getc ()) и

каждый раз, когда вы видите \n (а также в начале файла), вам нужно напечатать число с начальными нулями, а затем пробел.printf("%06d ",ln) ; это, вероятно, то, что вы хотите для этого.

1 голос
/ 30 апреля 2019

У вас большое количество мелких проблем для решения. Во-первых, если вы не используете несоответствующий компилятор, соответствующие объявления для main являются int main (void) и int main (int argc, char **argv) (которые вы увидите написанными с эквивалентным char *argv[]). См .: Стандарт C11 §5.1.2.2.1 Запуск программы p1 (черновик n1570) . См. Также: Что должно возвращать main () в C и C ++?

Далее c должен иметь тип int, а не тип char, чтобы соответствовать EOF, например,

    int c, last = 0; /* c must be type int, not char to match EOF */

Не кодировать имена файлов жестко и не использовать magic-numbers . Либо передайте имя файла в качестве аргумента main(), либо запросите его в вашей программе. Вы можете удобно взять имя файла для открытия или чтения из stdin по default с помощью троичного оператора следующим образом:

    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

Наконец, к вашему коду, так как вы хотите Префикс каждой строки с номером строки, вы должны вывести номер строки для первой строки Перед вы выводите символы для этой строки (и то же самое для каждой последующей строки). Вы можете сделать это, просто выдав сначала число (используя спецификатор преобразования "%06zu " с модификаторами '0' для вывода начальных нулей и ширина поля 6 в соответствии с указанным форматом). Также обратите внимание, что тип вашего счетчика ln изменен с int на size_t, рекомендуемый тип для счетчиков в C (у вас не может быть отрицательного количества строк).

Соединяя это с использованием символа last, чтобы разрешить проверку '\n' перед выводом ваших символов, вы можете сделать:

#include <stdio.h>

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

    int c, last = 0; /* c must be type int, not char to match EOF */
    size_t ln = 1;      /* use size_t for counters */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    printf ("%06zu ", ln++);            /* output line 1 number */
    while ((c = getc(fp)) != EOF) {     /* read each character */
        if (last)                       /* test if last set */
            putchar (last);             /* output all characters */
        if (last == '\n')               /* test if last is newline */
            printf ("%06zu ", ln++);    /* output next line number */
        last = c;                       /* set last to c */
    }
    putchar (last);                     /* output final character */
    if (last != '\n')                   /* check POSIX eof */
        putchar('\n');                  /* tidy up with newline */
    if (fp != stdin)                    /* close file if not stdin */
        fclose (fp);

    return 0;
}

( примечание: проверка if (last != '\n') после выхода из цикла проверяет наличие строки POSIX, заканчивающейся на последней строке, и если нет, вы должны вручную вывести '\n', чтобы ваша программа совместима с POSIX)

Пример входного файла

$ cat ../dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

Пример использования / Вывод

$ ./bin/linenos ../dat/captnjack_noeol.txt
000001 This is a tale
000002 Of Captain Jack Sparrow
000003 A Pirate So Brave
000004 On the Seven Seas.

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

( также обратите внимание: , если ваш компилятор не поддерживает спецификатор преобразования zu для size_t, удалите 'z' и выведите его как значение без знака - VS10 или более ранние версии не поддерживают zu)

0 голосов
/ 30 апреля 2019

Я бы рекомендовал не увеличивать счетчик строк с каждым '\n' и вместо этого увеличивать счетчик строк каждый раз, когда символ читается после a '\n'. Это также, когда код должен напечатать номер строки

unsigned long ln = 0;
int prev = '\n';
int c;  // Use int here, not char
while((c=getc(fp))!=EOF) {
  if (prev == '\n'){
    printf("%06lu ", ++ln);
  }
  putchar(c);
  prev = c;
}
if (prev != '\n') {
  putchar('\n');  // print a \n for input that lacks a final \n
}
printf("lines num: %lu\n", ln);

Обратите внимание, что вышеприведенное работает хорошо, когда есть 0 строк (нет данных) и когда ввод не заканчивается на '\n'.

Типичным недостатком использования fgets() является 1) когда длина строки превышает входной буфер, требуется специальная обработка 2) когда на входе неожиданно содержится нулевой символ , который загрязняет тропическую строку обработка. getchar() не имеет этих проблем.

0 голосов
/ 30 апреля 2019

Для нумерации строк или для изменения какой-либо части файла в этом случае лучше всего загрузить файл в память в виде строки, манипулировать этой строкой (в данном случае добавить номера строк), а затем создать пробелновый файл.Скопируйте измененную строку в новый файл, а затем переименуйте ее в путь к старому, чтобы перезаписать ее.

/* fp: File whose lines are to be numbered 
   pathOld: Its path */
void giveLineNos(FILE *fp, const char *pathOld)
{
    char line[MAXLINE]; /* line that is read in */
    char numbered[MAXLINE + 8]; /* line that will include its number */
    int i;

    char tempName[L_tmpnam];
    tmpnam(tempName);  /* generate filename guaranteed to be unique */

    FILE *fpNumbered = fopen(tempName, "w"); /* create temporary file onto 
                              which we will write; error checking omitted */

    for (i = 0; fgets(line, MAXLINE, fp) != NULL; ++i) {
        /* write out the line number followed by its contents */
        snprintf(numbered, MAXLINE + 8, "%d: ", i + 1);
        strcat(numbered, line);

        fputs(numbered, fpNumbered); /* save line to file */
    }

    rename(tempName, pathOld);  /* rename the temporary file to that of 
                                    the old one, thereby overwriting it */
    fclose(fpNumbered);
    fclose(fp);
}

Если вы хотите печатать только пронумерованные строки, даже не касаясь файлазатем вы заменяете оператор fputs в вышеприведенном коде на вызов printf:

/* fputs(numbered, fpNumbered); */ printf("%s", numbered);

(перевод новой строки после %s неправильный, поскольку fgets уже вводит новую строку вбуфер line, который затем передается в numbered.)

Также обратите внимание, что ваш main нестандартный.Используйте int в качестве типа возврата, а не void.

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