C Word Count программа

Я пытаюсь написать программу, которая будет подсчитывать количество символов, слов и строк в тексте, текст:

It was a dark and stormy night; the rain fell in torrents - except at occasional intervals, when it was checked by a violent gust of wind which swept up the streets (for it is in London that our scene lies), rattling along the housetops, and fiercely agitating the scanty flame of the lamps that struggled against the darkness. Edward Bulwer-Lytton's novel Paul Clifford. 

Я продолжаю получать 62 вместо 64 , любые предложения?

 #include  #include  #include  int main() { int tot_chars = 0; /* total characters */ int tot_lines = 0; /* total lines */ int tot_words = 0; /* total words */ int boolean; /* EOF == end of file */ int n; while ((n = getchar()) != EOF) { tot_chars++; if (isspace(n) && !isspace(getchar())) { tot_words++; } if (n == '\n') { tot_lines++; } if (n == '-') { tot_words--; } } printf("Lines, Words, Characters\n"); printf(" %3d %3d %3d\n", tot_lines, tot_words, tot_chars); // Should be 11 64 375 // rn is 11 65 375 return 0; } 

    В коде есть несколько проблем:

    • в тесте if (isspace(n) && !isspace(getchar())) вы потенциально потребляете байт из файла и не увеличиваете tot_chars , кроме того, вы не увеличиваете tot_words если два слова разделены двумя пробелами. Это вызывает darkness. и Edward считали одним словом.
    • вы уменьшаете tot_words когда видите дефис, что неверно, поскольку слова разделены только пробелом. Это заставляет Bulwer-Lytton's считаться 1-1 , т. Е. Ноль. Следовательно, вы получаете только 62 слова вместо 64.

    • в меньшей заметке имя n путается для байта, считанного из файла. Это обычно более подходящее имя для подсчета. Идиоматическое имя для байта, считанного из файла, является c , и тип корректен как int для размещения для всех значений unsigned char плюс специальное значение EOF .

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

     #include  #include  int main(void) { int tot_chars = 0; /* total characters */ int tot_lines = 0; /* total lines */ int tot_words = 0; /* total words */ int in_space = 1; int c, last = '\n'; while ((c = getchar()) != EOF) { last = c; tot_chars++; if (isspace(c)) { in_space = 1; if (c == '\n') { tot_lines++; } } else { tot_words += in_space; in_space = 0; } } if (last != '\n') { /* count last line if not linefeed terminated */ tot_lines++; } printf("Lines, Words, Characters\n"); printf(" %3d %3d %3d\n", tot_lines, tot_words, tot_chars); return 0; } 

    Оба следующих условия увеличивают количество слов на символах новой строки, а это означает, что каждое слово, за которым следует новая строка вместо пробела, подсчитывается дважды:

     if (isspace(n) || n == '\n'){ tot_words++; } if (n=='\n'){ tot_lines++; tot_words++; } 

    Если вы избавитесь от || n == '\n' || n == '\n' бит, вы должны получить правильный счет.

    + Изменить

      if (n=='\n'){ tot_lines++; tot_words++; } 

    в

      if (n=='\n'){ tot_lines++; } 

    Вы уже считаете слово на новой строке в

      if (isspace(n) || n == '\n'){ tot_words++; } 

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

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

    Я думаю, что ваш последний, if блок действительно грязный, вы используете ispunct() для уменьшения tot_words но ваши слова в тексте используют знаки препинания в них (без пробелов). Это означает, что они являются частью слов. поэтому вы не должны их уменьшать.

    Раньше я думал, что мы должны проверять только символ « -' в последнем блоке, if он используется в первом абзаце текста с пробелами, но он также снова используется в имени Novel без какого-либо пробела, поэтому я думаю, что вы должны полностью игнорировать последний if блокировать и рассматривать '-' как слово для простоты логики.

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

     if (isspace(n)) // isspace() checks for whitespace characters ' ', '\t', '\n','\r, so no need to write like this (isspace(n) || n == '\n') boolean=0; //outside of word. else if(boolean==0){ tot_words++; boolean=1; //inside of word. } if (n=='\n') tot_lines++; 

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

    Присоединение вывода, которое я получил после запуска кода. Выход введите описание изображения здесь

     $ ./a.out " ab " "abc " "abcd" s = ab , words_cnt= 2 s = abc , words_cnt= 3 s = abcd, words_cnt= 4 $ ./a.out "It was a dark and stormy night; > the rain fell in torrents - except ...... Edward Bulwer-Lytton's novel Paul Clifford., words_cnt = 64 

     #include  #include  #include  #include  int count_words(const char *s) { int i, w; for (i = 0, w = 0; i < strlen(s); i++) { if (!isspace(*(s+i))) { w++; while (!isspace(*(s+i)) && *(s+i) != '\0') { i++; } } } return w; } int main(int argc, const char *argv[]) { int i; if (argc < 2) { printf("[*] Usage: %s   ...\n", argv[0]); return -1; } for (i = 1; i < argc; i++) { printf("s = %s, words_cnt= %d\n ", argv[i], count_words(argv[i])); } return 0; }