tmp += cur;
last = cur;
}
}
int main(int argc, char** argv) {
if (argc < 3)
return(EXIT_FAILURE);
int w = 72;
ifstream in(argv[1]);
ofstream out(argv[2]);
if (!in || !out)
return(EXIT_FAILURE);
if (argc == 4) w = atoi(argv[3]);
textWrap(in, out, w);
out.close();
if (out)
return(EXIT_SUCCESS);
else
return(EXIT_FAILURE);
}
textWrap
читает по одному символы из входного потока. Каждый символ добавляется к временной строке tmp
до тех пор, пока не будет достигнут конец слов или максимальная длина строки. Если достигнут конец слова, а максимальная длина строки еще не достигнута, то временная строка записывается в выходной поток. В противном случае, если максимальная длина строки была превышена, в выходной поток записывается новая строка, пробел в начале временной строки удаляется, и строка записывается в выходной поток. Таким образом, textWrap
записывает в выходной поток столько, сколько можно, но не превышая максимальной длины строки. Вместо разделения слов она переносит все слово на новую строку.
Пример 4.25 использует потоки почти так же, как и рецепт 4.15. За дополнительной информацией о потоках и их использовании обратитесь к этому рецепту.
Рецепт 4.15.
4.17. Подсчет числа символов, слов и строк в текстовом файле
Требуется подсчитать число символов, слов и строк — или каких-либо других элементов текста — в текстовом файле.
Для чтения символов по одному используйте входной поток и по мере чтения символов, слов и строк увеличивайте счетчики. Пример 4.26 содержит функцию countStuff
, которая именно это и делает.
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cctype>
using namespace std;
void countStuff(istream& in,
int& chars, int& words, int& lines) {
char cur = ' ';
char last = ' ';
chars = words = lines = 0;
while (in.get(cur)) {
if (cur == '
' ||
(cur == 'f' && last == '
'))
lines++;
else chars++;
if (!std::isalnum(cur) && // Это конец
std::isalnum(last)) // слова
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 << '
';
cout << 'слов: ' << w << '
';
cout << 'строк: ' << l << '
';
}
Этот алгоритм очень прост. С символами все просто: увеличивайте счетчик символов при каждом вызове get
для входного потока. Со строками все не намного сложнее, так как способ представления концов строк зависит от операционной системы. К счастью, обычно это либо символ новой строки (
), либо последовательность из символов возврата каретки и перевода строки (
). Отслеживая текущий и предыдущий символы, можно легко обнаружить вхождения этой последовательности. Со словами все проще или сложнее, в зависимости от определения того, что такое «слово».
Для примера 4.26 я предположил, что слово это неразрывная последовательность буквенно- цифровых символов. В процессе просмотра каждого символа входного потока при обнаружении неалфавитно-цифрового символа я проверяю предыдущий символ — был ли он буквенно-цифровым или