Подсчет пустых строк из файла в C

Есть ли способ подсчитать общее количество пустых строк в файле на языке C. Я пытался, и ниже мой код, но он не работает.

void countLines(char *f1)
{
  FILE *fp;
  fp=fopen(f1,"r");
  int d=fgetc(fp),count=0,countbl=0;
  while(d != EOF)
  {
    if(d=='\n')
    {
      d=fgetc(fp);
      if(d=='\n')
        countbl++;
      count++;
      fseek(fp,-1,SEEK_CUR);
    }

    d=fgetc(fp);
  }
  printf("%d %d",count+1,countbl);
}

Я использую fgetc для чтения файла charcater by charcater, когда fgetc встречает \n. Я проверяю следующий символ, если он снова \n, это означает, что это пустая строка, но она не работает.

Образец ввода

fileCount.txt(name of text file)

Содержимое файла

This is line one


Hello, welcome to programming

Code quotient - Get better at coding

b

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

8 4

Здесь 8 — общее количество строк, а 4 — общее количество пустых строк.

Вот новый код, но он все еще не работает

void countLines(char *f1)
{
  FILE *fp;
  fp=fopen(f1,"r");
  int d=fgetc(fp),count=0,countbl=0,temp=0;
  while(d != EOF)
  {
    //printf("%c %c",temp ,d);
    if(d=='\n' && temp=='\n' )
      countbl++;
    if(d=='\n')
    count++;
    temp=d;

    d=fgetc(fp);
  }
  printf("%d %d",count+1,countbl);
}

person Tom    schedule 30.04.2020    source источник
comment
Для чего нужен fseek?   -  person John3136    schedule 30.04.2020
comment
fseek — громоздкий способ ungetcобозначения персонажа. Оба они не нужны, если вы сохраняете значение ранее прочитанного символа (и инициализируете его значением '\n', так что символ новой строки в начале считается пустой строкой). Смотрите назад, а не вперед. Ведь '\n' стоит в конце строки, значит вас интересует то, что вы уже видели.   -  person M Oehm    schedule 30.04.2020
comment
@ John3136 в первом условии if d=fgetc(fp) сдвинет указатель на следующий символ, чтобы переместить указатель на один шаг назад, я использовал fseek   -  person Tom    schedule 30.04.2020
comment
@MOehm Не могли бы вы рассказать мне, как ведет себя fgets, когда встречает пустую строку?   -  person Tom    schedule 30.04.2020
comment
fgets не встречает пустых строк, он встречает одиночные символы. Вы, как программист, должны определить, есть ли пустая строка. Кстати, ваше определение двух последовательных новых строк очень узкое. Пустая строка может содержать пробелы и символы табуляции.   -  person M Oehm    schedule 30.04.2020
comment
@MOehm будет ли строка считаться пустой, если в ней есть пробелы и табуляция?   -  person Tom    schedule 30.04.2020
comment
Что ж, строки, в которых есть только пробелы, для меня выглядят как пустые строки, но то, что ваша программа должна считать их пустыми или нет, зависит от вашей задачи.   -  person M Oehm    schedule 30.04.2020
comment
@MOehm проверьте новый код, все еще не работает   -  person Tom    schedule 30.04.2020
comment
Пожалуйста, вместо того, чтобы говорить, что это не работает, постарайтесь описать, что не работает. Какие ошибки вы получаете? Где ваш фактический результат отличается от предполагаемого результата?   -  person M Oehm    schedule 30.04.2020
comment
@MOehm Согласно новому коду, он должен считать пустые строки, но кажется, что это условие if(d=='\n' && temp=='\n' ) никогда не выполняется и в результате countnl остается равным нулю   -  person Tom    schedule 30.04.2020
comment
Почему вы так думаете? Если у вас пусто, ваш новый код должен работать, за исключением того, что вы печатаете count + 1 вместо просто count.   -  person M Oehm    schedule 30.04.2020
comment
@MOehm Это не работает, countnl остается нулем, и я добавил 1 к count, потому что EOF будет достигнуто в последней строке и не будет подсчитано, но я также должен подсчитать общее количество строк.   -  person Tom    schedule 30.04.2020
comment
Ваши строки действительно пусты, то есть имеют нулевую длину? Не могли бы вы проверить это в редакторе? Я также разместил ответ ниже, который заботится о пустых, но не пустых строках. Вы также можете попробовать это, если хотите.   -  person M Oehm    schedule 30.04.2020


Ответы (2)


Во-первых, давайте определим структуру для хранения статистики строки, чтобы мы могли вернуть t из функции:

struct linestat {
    size_t total;
    size_t blank;
};

Далее давайте определим, что представляет собой пустую строку. Ваше определение двух последовательных символов новой строки правильное, но довольно узкое, поэтому допустим, что пустая строка состоит только из символов пробела и заканчивается символом новой строки. Вы можете определить, является ли символ c пробелом или нет, с помощью функции isspace(c) из <ctype.h>.

Вы можете пойти об этом по-разному. Вот один из способов:

Сканируйте строку, пока не увидите символ новой строки, и следите за тем, не встретите ли вы пробелы на своем пути. Перечитал эту строчку в твоей статистике. повторение. Вы также должны проверить, сталкиваетесь ли вы с EOF, конечно:

struct linestat count_lines(const char *filename)
{
    struct linestat ls = {0, 0};
    FILE *fp = fopen(filename, "r");

    if (fp == 0) return ls;

    while (1) {
        int blank = 1;
        int c = fgetc(fp);

        while (c != EOF && c != '\n') {
            if (isspace(c) == 0) blank = 0;

            c = fgetc(fp);
        }

        if (c == EOF) break;

        ls.total++;
        if (blank) ls.blank++;
    }

    fclose(fp);

    return ls;
}

Заметки:

  • Алгоритм отслеживает то, что он видит по пути, так что вам никогда не придется переходить назад в файле. (Иногда может оказаться полезным сделать один символ непрочитанным. В таких случаях ungetc лучше, чем fseeking.)
  • Я решил использовать здесь while (1) с break, потому что я думаю, что это лучше соответствует тому, как работает процедура. Обратите внимание, что последняя строка файла не будет учитываться, если она не завершается должным образом символом новой строки.
  • Вы должны отловить случай, когда данный файл не может быть открыт для чтения. После того как вы fopen отредактировали файл, вы должны fclose сделать его позже.
person M Oehm    schedule 30.04.2020

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

Вот код

void countLines(char *f1)
{
  FILE *fp;
  fp=fopen(f1,"r");
  int count=0,countbl=0;
  char str[200],*c1;
  c1=fgets(str,200,fp);
  while(c1 != NULL)
  {
    if(c1[0]>=32 && c1[0]<=127)
    countbl++;
    c1=fgets(str,200,fp);
    count++;
  }
  printf(" %d %d",count,count-countbl);
}
person Tom    schedule 30.04.2020