Счетчик слов и предложений из указанного пользователем файла - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь создать счетчик, который будет считать слова и предложения из текстового файла. Я изо всех сил пытаюсь внедрить alphanumeri c finder в программу. Мне нужна помощь. Вот что я получил до сих пор. Программа не считается правильно. Это продолжает считать пробелы.

 int main (void)
{
    // Local Variables
    char         path[30] ; // File path size
    unsigned int words   ; //total number of words
    unsigned int sentences ; //total number of sentences
    char ch ;

    FILE *file; // text file to be opened

    // Intialize counter variables
    words = 0;
    sentences = 0;

    //prompt user for file path
    printf ("enter source file path: ");

    //stores the file name in path.
    scanf ( "%s" , path);

    //reads file name
    file = fopen ( path , "r");

    //check if file name is valid
    if ( file == NULL )
    {
       printf ( "Please enter a valid file name" );
    }

    //while function to count sentences and words
    while (( ch = fgetc(file)) != EOF  )
    {
        // check for a period, exclamation or question mark.
        //if true count sentence
        if ( (ch == '.') || (ch == '!') || (ch == '\?') )
        {
            sentences++;
        }


        // if there is a space or tab or space is true. count words
        else if ( ch == ' ' || ch == '\t'  )
        {

        words++;
         }

        }
    //displays to the user the amount of words and sentences in the text file.
    printf ( "total words = %d\n" , words );
    printf ( "total sentences = %d\n" , sentences);


}

1 Ответ

1 голос
/ 22 апреля 2020

Как уже упоминал Арку, вы, вероятно, хотите защититься от нескольких пробелов или нескольких периодов и т. Д. c. давая вам ложное число, которое слишком велико.

Вы можете обработать это с помощью дополнительной переменной состояния / типа.

Вот небольшой рефакторинг вашего кода (обратите внимание, что switch/case является немного чище). Кроме того, я добавил новую строку (\n) в качестве разделителя слов и изменил '\?' на '?':

//while function to count sentences and words
int type = -1;
while ((ch = fgetc(file)) != EOF) {
    switch (ch) {
    // check for a period, exclamation or question mark.
    // if true count sentence
    case '.':
    case '!':
    case '?':
        if (type != 1)
            sentences++;
        type = 1;
        break;

    // if there is a space or tab or space is true. count words
    case ' ':
    case '\t':
    case '\n':
        if (type != 2)
            words++;
        type = 2;
        break;

    default:
        type = 0;
        break;
    }
}

ОБНОВЛЕНИЕ:

Я до сих пор не понимаю, как я могу использовать isalnum (). Извините, я не очень хорош в этом. Но я хочу, чтобы программа сначала проверила запуск поиска мира.

Хорошо, я добавил больше комментариев и добавил использование isalnum. Я модулировал код и немного изменил алгоритм.

Я создал две версии сканирования l oop.

По умолчанию аналогично original

Второе строится, если определено FAST_LOOKUP. Здесь используется таблица поиска вместо switch, так что это быстрее. Таблица создается один раз динамически. Это быстрее, потому что switch заменяется поиском в таблице (то есть одной выборкой из памяти), поэтому для больших файлов это выигрыш.

Чтобы исключить время, необходимое для инициализации таблицы, это может быть определенным статически с инициализаторами, что и делается в ctype.h

В любом случае, вот обновленный код:

// types of characters
// NOTE: with an enum like this, the values start at 0 and increment by 1,
// so TYPE_OTHER=0, TYPE_QUOTE=1, ...
enum {
    TYPE_OTHER,                         // something else
    TYPE_QUOTE,                         // single or double quote
    TYPE_DOT,                           // sentence ender: period/exclam/quest
    TYPE_SPACE,                         // whitespace: space/tab/comma/newline
    TYPE_ALPHA,                         // alphanumeric: isalnum is true
};

int words = 0;                          // count of words
int sentences = 0;                      // count of sentences
int oldtype = TYPE_DOT;                 // type of _previous_ char
int newtype;                            // type of current char
int skipflg;                            // 1=ignore current character
int chgflg;                             // 1=type is changing, 0=no change

#ifdef FAST_LOOKUP
char type_lookup[256];                  // fast lookup table
#endif

// chartype -- decide type of current char
int
chartype(int ch)
{
    int newtype;

    switch (ch) {
    case '\'':  // single quote (e.g. don't, a man's ego, womens' lingerie)
    case '"':  // double quote (e.g. a phrase: "quick brown fox")
        newtype = TYPE_QUOTE;
        break;

    case '.':  // sentence ender
    case '!':
    case '?':
        newtype = TYPE_DOT;
        break;

    case ' ':  // whitespace
    case '\t':
    case ',':
    case '\n':
    case '_':
        newtype = TYPE_SPACE;
        break;

    default:  // other
        if (isalnum(ch))
            newtype = TYPE_ALPHA;
        else
            newtype = TYPE_OTHER;
        break;
    }

    return newtype;
}

// loop -- standard lookup
void
loop(void)
{
    int ch;

    // do one time initialization of fast lookup table
#ifdef FAST_LOOKUP
    if (type_lookup[' '] == 0) {
        for (ch = 0;  ch < 256;  ++ch)
            type_lookup[ch] = chartype(ch);
    }
#endif

    while (1) {
        // get next char and stop on EOF
        // NOTE: this construct is cleaner/simpler than the compound while
        // statement and the optimizer will generate _exactly_ the same object
        // code
        ch = fgetc(file);
        if (ch == EOF)
            break;

        // get type of character
#ifdef FAST_LOOKUP
        newtype = type_lookup[(unsigned char) ch];
#else
        newtype = chartype(ch);
#endif

        // ignore some punctuation (e.g. quotation marks) and do so _invisibly_
        // that is, _don't_ change state
        if (newtype == TYPE_QUOTE)
            continue;

        // are we changing state/type of char?
        // we're primarily interested only in the first transition at a given
        // moment
        // NOTE: this is guaranteed to be either 0 or 1 (so, we can add to
        // counts without a further if statement)
        chgflg = (oldtype != newtype);

        switch (newtype) {
        case TYPE_DOT:  // sentence ender
            sentences += chgflg;
            break;

        case TYPE_ALPHA:  // alpha char (_must_ be first) -- start of word
            words += chgflg;
            break;
        }

        // remember type of _current_ char for the next loop iteration
        oldtype = newtype;
    }
}

Вот что isalnum et. и др. использовать. Они просто индексируют в таблицу, которая имеет «атрибуты» для каждого символа (например):

 short ctype[256] = {
     ['a'] = FLAG_ALPHA,
     ['0'] = FLAG_NUMBER
 };

isalnum определяется как [не точно, но ...]:

#define isalnum(ch)   (ctype[(unsigned char) ch] & (FLAG_ALPHA | FLAG_NUMBER))

Обратитесь к фактическому ctype.h файлу для реальных / реальных деталей

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