02.01.2009
Известно, что для того, чтобы текстовый файл правильно отображался в браузере, необходимо в нем расставить изрядно количестов тегов. (как правило десятки и сотни). Однажды я написал утилиту, которая расставляет теги (так, как мне надо, а не так как в Word). Затем написал утилиту, которая "обезвреживает" теги, то есть делает их видимыми в браузере. Эти программы служат мне верой и правдой уже долгое время.
Но назрела необходимость иметь утилиту для удаления тегов из html-файла. И тут я счасливо нахожу эту утилиту в книге Брюса Эккеля "Thinking in C++". Написана она мастерски! Ничего лишнего.
Ниже представлен вариант программы удаления тегов из html-файла из 3-главы Брюса Эккеля.
По сравнению с предыдущей версией, эта программа считывает исходный файл inFile с тегами,
и переписывает его в результирующий файл outFile без тегов.
Для этого пришлось изменить лишь несколько строк в главной функции main()
Измененная функция main()
int main(int argc, char* argv[]) {
ifstream in("inFile", ios::binary);
if (!in)
{
cout << "Unable to open " << "inFile" << " for reading.\n";
return(1);
}
ofstream out("outFile",ios::binary);
if (!out)
{
cout << "Unable to open " << "outFile" << " for writing.\n";
return(1);
}
string s;
while(getline(in, s))
if (!stripHTMLTags(s).empty())
out << s << endl;
} ///:~
Ниже показана вся модифицированная программа.
Вверх
Фильтр для удаления тегов и маркеров HTML (новый вариант)
string& stripHTMLTags(string& s) {
int main(int argc, char* argv[]) { ofstream out("outFile",ios::binary);
string s;
Анализ:
Программа удаляет даже теги html, занимающие несколько строк. Для этого используется статический флаг inTag, которому присваивается true, если при обнаружении начального тега парный завершающий тег не был обнаружен в той же строке. В функции stripHTMLTags() встречаются все формы функции erase().
Используемая версия getline() представляет собой глобальную функцию, объявленную в заголовочном файле <string> она удобна тем, что в аргументе string может храниться строка произвольной длины. Нам не приходится беспокоиться о размерах символьного массива, как при использовании функции stream::getline().
В программе задействована функция replaceAll(), упоминавшаяся ранее в этой главе. В следующей главе будет создано более элегантное решение с применением строковых потоков.
Внутри программы удаления тегов есть функция replaceAll(), которая заменяет любую подстроку
в строке на новую подстроку (конкретно в этой программе она использована для замены маркеров). Функция replaceAll() оформлена в виде двух отдельных файлов -
заголовочного h-файла и cpp-файла. Нахожу эту функцию весьма полезной!
Вверх
Функция замены всех вхождений одной подстроки - другой подстрокой:
std::string& replaceAll(string& context,
string& replaceAll(string& context, const string& from,
const string& to) {
Версия find(), использованная в этой программе, получает во втором аргументе начальную позицию поиска, и возвращает string::npos. Позицию, хранящуюся в переменной lookHere, важно сместить за строку замены на тот случай, если from является подстрокой to.
//: C03:HTMLStripper.cpp {RunByHand}
//{L} ReplaceAll
// Фильтр для удаления тегов и маркеров HTML
#include <cassert>
#include <cmath>
#include <cstddef>
#include <fstream>
#include <iostream>
#include <string>
#include "ReplaceAll.h"
//#include "../require.h"
using namespace std;
bool done = false;
while (!done) {
// Продолжаем поиск '>'.
size_t rightPos = s.find('>');
if (rightPos != string::npos) {
s.erase(0, rightPos + 1);
else {
s.erase();
else {
size_t leftPos = s.find('<');
if (leftPos != string::npos) {
size_t rightPos = s.find('>');
if (rightPos == string::npos) {
s.erase(leftPos);
else
else
// Удаление всех специальных символов HTML
replaceAll(s, "& lt;", "& lt");
replaceAll(s, "& gt;", "& gt");
replaceAll(s, "& amp;", "&");
replaceAll(s, "& nbsp;", " ");
// E o. a.
return s;
ifstream in("inFile", ios::binary);
if (!in)
{
return(1);
if (!out)
{
return(1);
while(getline(in, s))
if (!stripHTMLTags(s).empty())
out << s << endl;
//: C03:ReplaceAll.h
#ifndef REPLACEALL_H
#define REPLACEALL_H
#include <string>
const string& from, const string& to);
#endif // REPLACEALL_H ///:~
//: C03:ReplaceAll.cpp {O}
#include <cstddef>
#include "ReplaceAll.h"
using namespace std;
size_t foundHere;
while ((foundHere = context.find(from, lookHere))
!= string::npos) {
lookHere = foundHere + to.size();
return context;
Анализ: