Как уже упоминал Арку, вы, вероятно, хотите защититься от нескольких пробелов или нескольких периодов и т. Д. 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
файлу для реальных / реальных деталей