Как подсчитать общее количество слов без использования строки?

Я реализовал этот код для получения no. количества слов. Он отлично работает для всех одиночных символов, то есть если я ввожу "q w r " в качестве ввода, он дает мне 3 слова, но когда я ввожу "qwe ed df " в качестве ввода, он отображает 2.

#include<stdio.h>
int main()
{
    int c=getchar();

    int words=0;

    while(c!=EOF)
    {
        if(c==' ' || c=='\n')
        {
            c=getchar();
        }
        else if(c>='a' && c<='z')
        {  
            c=getchar();

            if(c==' ')
            {
                words=words+1;
                c=getchar();
            }
            else
            {
               c=getchar();
            }
        }
    }
    printf("%i\n",words);
}

person himanshu jhamb    schedule 15.08.2016    source источник
comment
Обычный метод заключается в использовании while ((c = getchar()) != EOF) — вы получаете кредит за использование int c;, а не char c;, кстати — а затем в цикле отслеживайте «я в слове». Если вы в слове и читаете без пробела, вы все равно в слове. Если вы в слове и читаете пробел, вы закончили слово (и больше не находитесь в слове). Если вы не в слове и получаете символ без пробела, вы теперь в слове; увеличить счетчик слов. Если вы не в слове и получаете пробел, вы все равно не в слове. Заголовок <ctype.h> содержит макросы классификации символов.   -  person Jonathan Leffler    schedule 15.08.2016
comment
read находится в одном месте Или предпросмотр и ungetc.   -  person BLUEPIXY    schedule 15.08.2016
comment
Если файлы большие, рассмотрите возможность буферизации чтения (например, char buf[1024] = ""; while (fgets (buf, 1024, stdin)) { char *p = buf; [your logic here]}). Причина в том, что операции в памяти выполняются на порядки быстрее, чем файловый ввод-вывод по одному символу за раз. (вы можете выбрать размер buf любым, имеющим смысл. вы увидите значительное улучшение с буферами размером всего 8 символов)   -  person David C. Rankin    schedule 15.08.2016


Ответы (5)


Хитрость заключается в том, чтобы считать границы.

В исходном коде есть ошибка...

        if(c==' ')
        {
            words=words+1;
            c=getchar();
        }

Код подсчитывает слова только в том случае, если пара операций чтения приводит к 'a' => 'z', за которыми следует ' '.

Хитрость заключается в том, чтобы упростить цикл до цикла чтения по одному символу за раз. (Это гарантирует, что странные границы не возникнут) и конечный автомат, который моделирует, едите ли вы слова или пробелы.

enum Mode { word = 1, spaces = 2 };
int c=getchar();
enum Mode currentMode = spaces;
int words=0;

while(c!=EOF)
{
    if(c==' ' || c=='\n')
    {
        if( currentMode == word ) {
            words=words+1;
        }
        currentMode = spaces;
    }
    else if(c>='a' && c<='z')
    {  
        currentMode = word;
    }
c=getchar();
}
// count the last word...
if( currentMode == word ) {
    words=words+1;
}

Код теперь будет игнорировать любой не-альфа-символ, как ни слово, ни пробел.

РЕДАКТИРОВАТЬ: исправлено неправильное использование перечисления

person mksteve    schedule 15.08.2016
comment
Я думаю, вы неправильно назначаете состояние режима? (пробелы и слова меняются местами) - person Daniel Jour; 15.08.2016
comment
Спасибо @Daniel-Jour - исправлено - person mksteve; 15.08.2016
comment
Это интересно — вы определяете окончания слов. Если вы обнаружили начало слов, вы можете избежать приращения после цикла. Вы бы просто удалили условие в блоке «если это пробел» и его приращение, а также приращение, когда вы начинаете слово (в блоке «иначе, если»). Я думаю, что это даст тот же ответ. - person Jonathan Leffler; 15.08.2016

Проблема с вашим кодом заключается в ваших разрозненных вызовах getchar, которые скрывают ошибку, которую вы видите.

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

Что-то типа:

while ((c = getchar()) != EOF) {
     if (c == ' ' || c == '\n') {

     } else if (c >= 'a' && c <= 'z')

     } else {

    }
}

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

Заполните пробелы в приведенном выше, и это должно работать. (А затем проверьте с заглавными буквами!).

person dave    schedule 15.08.2016
comment
снова в операторе else if я должен вызвать функцию getchar(), чтобы увидеть, введен ли пробел после буквы или нет .... тогда какая разница в предыдущем коде? - person himanshu jhamb; 15.08.2016
comment
@himanshujhamb: Нет, не делай этого, вот откуда твои проблемы. Вы можете отслеживать предыдущую букву или иметь флажок, который отмечает, были ли вы ранее в слове. - person dave; 16.08.2016

Вы читаете символы в слишком многих местах цикла while. Это причина получения неправильного вывода. Попробуйте использовать этот цикл:

while(c!=EOF)
{
    while(c == ' ' || c == '\n') //consume multiple spaces
    {
        c = getchar();
    }

    for( int i=0 ;c >= 'a' && c <= 'z'; i++) //consuming a word
    {
        if(i == 0) //increment word count once at the start of each word
        {
            words++;
        }

        c = getchar();
    }

}
person Cherubim    schedule 15.08.2016
comment
да, у вас могут быть люди с жалобой. но я думаю, что этот шнур работает в реалистичном диапазоне. - person BLUEPIXY; 15.08.2016

у вашего кода есть проблема со строками, которые имеют

Я думаю, четное количество символов

логика программы не совсем в порядке, вам нужно добавить это условие внутри последнего else :

 if(c==' ')
   {
     words=words+1;
     c=getchar();
   }

программа будет такой:

  #include <stdio.h>

int main()
{
   int c=getchar();

    int words=0;

    while(c!=EOF)
    {
        if(c==' ' || c=='\n')
        {
            c=getchar();
        }
        else if(c>='a' && c<='z')
        {  
            c=getchar();
            if(c==' ')
            {
                words=words+1;
                c=getchar();
            }
            else
            {
               c=getchar();
               if(c==' ')
                {
                words=words+1;
                c=getchar();
                }
            }
        }
    }
    printf("%d\n",words);
    return 0;
}

потому что, когда вы вводите строку из двух символов и добавляете пробел, этот последний пробел будет прочитан последним getchar внутри оператора else, который не увеличивает количество слов.

проверьте эти результаты.

Надеюсь, это поможет!

person Sadmi    schedule 15.08.2016
comment
Вы видели приведенные выше результаты? Вот они снова Результаты.... . - person Sadmi; 16.08.2016

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

// Useful is...() functions declared here.
#include <ctype.h>

unsigned long long words = 0;
int previous = ' ';
int ch;
while ((ch = getchar()) != EOF) {
  if (isspace(previous) && isalpha(ch)) words++;
  previous = ch;
}
 printf("%llu\n",words);

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

person chux - Reinstate Monica    schedule 15.08.2016