words++;

  last = cur;

 }

 if (chars > 0) {         // Изменить значения слов

  if (std::isalnum(last)) // и строк для специального

   words++;               // случая

  lines++;

 }

}

int main(int argc, char** argv) {

 if (argc < 2)

  return(EXIT _FAILURE);

 ifstream in(argv[1]);

 if (!in)

  exit(EXIT_FAILURE);

 int c, w, l;

 countStuff(in, c, w, l);

 cout << "символов: " << c << '\n';

 cout << "слов: " << w << '\n';

 cout << "строк: " << l << '\n';

}

Обсуждение

Этот алгоритм очень прост. С символами все просто: увеличивайте счетчик символов при каждом вызове get для входного потока. Со строками все не намного сложнее, так как способ представления концов строк зависит от операционной системы. К счастью, обычно это либо символ новой строки (\n), либо последовательность из символов возврата каретки и перевода строки (\r\n). Отслеживая текущий и предыдущий символы, можно легко обнаружить вхождения этой последовательности. Со словами все проще или сложнее, в зависимости от определения того, что такое «слово».

Для примера 4.26 я предположил, что слово это неразрывная последовательность буквенно-цифровых символов. В процессе просмотра каждого символа входного потока при обнаружении неалфавитно-цифрового символа я проверяю предыдущий символ — был ли он буквенно-цифровым или нет. Если был то это конец слова, и я увеличиваю счетчик слов. Определить, является ли символ буквенно-цифровым, можно с помощью функции isalnum из . Но это еще не все — с помощью аналогичных функций можно проверять символы на целый ряд других качеств. Функции, которые предназначены для проверки характеристик символов, приведены в табл. 4.3. Для широких символов используйте функции с такими же именами, но с буквой «w» после «is», например iswSpace. Версии для широких символов объявлены в заголовочном файле .

Табл. 4.3. Функции для проверки символов из и

ФункцияОписание
isalpha iswalphaБуквенные символы: a-z, A-Z (верхний или нижний регистр)
isupper iswupperБуквенные символы верхнего регистра: A-Z
islower iswlowerБуквенные символы нижнего регистра: a-z
isdigit iswdigitЧисловые символы: 0-9
isxdigit iswxdigitШестнадцатеричные числовые символы: 0-9, a-f, A-F
isspace iswspaceПробельные символы. ' ', \n, \t, \v, \r, \l
iscntrl iswcntrlУправляющие символы: ASCII 0-31 и 127
ispunct iswpunctСимволы пунктуации, не принадлежащие предыдущим группам
isalnum iswalnumisalpha или isdigit равны true
isprint iswprintПечатаемые символы ASCII
isgraph iswgraphisalpha, isdigit или ispunct равны true

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

Методика использования потоков в примере 4.26 почти идентична той, которая описана в рецептах 4.14 и 4.15, но несколько проще, так как он только исследует файл, не внося никаких изменений.

Смотри также

Рецепты 4.14 и 4.15.

<p>4.18. Подсчет вхождений каждого слова в текстовом файле</p>Проблема

Требуется подсчитать количество вхождений в текстовом файле каждого слова.

Решение

Для чтения из текстового файла непрерывных фрагментов текста используйте operator>>, определенный в , а для сохранения каждого слова и его частоты в файле используйте map, определенный в . Пример 4.27 демонстрирует, как это делается.

Пример 4.27. Подсчет частоты слов

1  #include

Перейти на страницу:

Похожие книги