Решение
Напишите функцию, которая использует входной и выходной потоки, читает символы с помощью istream::get(char), выполняет какие-либо действия и записывает символы с помощью ostream::put(char). Пример 4.25 показывает, как это делается с файлом, который содержит обычный текст, с учетом сохранения целостности слов.
Пример 4.25. Перенос текста
#include
#include
#include
#include
#include
#include
using namespace std;
void textWrap(istream& in, ostream& out, size_t width) {
string tmp;
char cur = '\0';
char last = '\0';
size_t i = 0;
while (in.get(cur)) {
if (++i == width) {
ltrimws(tmp); // ltrim как в рецепте
out << '\n' << tmp; // 4.1
i = tmp.length();
tmp.clear();
} else if (isspace(cur) && // Это конец
!isspace(last)) { // слова
out << tmp;
tmp.clear();
}
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, которая именно это и делает.
Пример 4.26. Подсчет статистики по текстовому файлу
#include
#include
#include
#include
using namespace std;
void countStuff(istream& in,
int& chars, int& words, int& lines) {
char cur = '\0';
char last = '\0';
chars = words = lines = 0;
while (in.get(cur)) {
if (cur == '\n' ||
(cur == '\f' && last == '\r'))
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 << '\n';
cout << "слов: " << w << '\n';
cout << "строк: " << l << '\n';
}
Обсуждение
Этот алгоритм очень прост. С символами все просто: увеличивайте счетчик символов при каждом вызове getдля входного потока. Со строками все не намного сложнее, так как способ представления концов строк зависит от операционной системы. К счастью, обычно это либо символ новой строки ( \n), либо последовательность из символов возврата каретки и перевода строки ( \r\n). Отслеживая текущий и предыдущий символы, можно легко обнаружить вхождения этой последовательности. Со словами все проще или сложнее, в зависимости от определения того, что такое «слово».
Для примера 4.26 я предположил, что слово это неразрывная последовательность буквенно-цифровых символов. В процессе просмотра каждого символа входного потока при обнаружении неалфавитно-цифрового символа я проверяю предыдущий символ — был ли он буквенно-цифровым или нет. Если был то это конец слова, и я увеличиваю счетчик слов. Определить, является ли символ буквенно-цифровым, можно с помощью функции isalnumиз . Но это еще не все — с помощью аналогичных функций можно проверять символы на целый ряд других качеств. Функции, которые предназначены для проверки характеристик символов, приведены в табл. 4.3. Для широких символов используйте функции с такими же именами, но с буквой «w» после «is», например iswSpace. Версии для широких символов объявлены в заголовочном файле .
Читать дальше