Borrar caracteres es fácil y eficiente con la función miembro
erase()
, que toma dos argumentos: donde
empezar a borrar caracteres (que por defecto es 0), y cuantos
caracteres borrar (que por defecto es
string::
npos
). Si
especifica más caracteres que los que quedan en el string, los
caracteres restantes se borran igualmente (llamando
erase()
sin argumentos borra todos los
caracteres del string
). A veces es útil
abrir un fichero HTML y borrar sus etiquetas y caracteres
especiales de manera que tengamos algo aproximadamente igual
al texto que obtendríamos en el navegador Web, sólo como un
fichero de texto plano. El siguiente ejemplo usa
erase()
para hacer el trabajo:
//: C03:HTMLStripper.cpp {RunByHand} //{L} ReplaceAll // Filter to remove html tags and markers. #include <cassert> #include <cmath> #include <cstddef> #include <fstream> #include <iostream> #include <string> #include "ReplaceAll.h" #include "../require.h" using namespace std; string& stripHTMLTags(string& s) { static bool inTag = false; bool done = false; while(!done) { if(inTag) { // The previous line started an HTML tag // but didn't finish. Must search for '>'. size_t rightPos = s.find('>'); if(rightPos != string::npos) { inTag = false; s.erase(0, rightPos + 1); } else { done = true; s.erase(); } } else { // Look for start of tag: size_t leftPos = s.find('<'); if(leftPos != string::npos) { // See if tag close is in this line: size_t rightPos = s.find('>'); if(rightPos == string::npos) { inTag = done = true; s.erase(leftPos); } else s.erase(leftPos, rightPos - leftPos + 1); } else done = true; } } // Remove all special HTML characters replaceAll(s, "<", "<"); replaceAll(s, ">", ">"); replaceAll(s, "&", "&"); replaceAll(s, " ", " "); // Etc... return s; } int main(int argc, char* argv[]) { requireArgs(argc, 1, "usage: HTMLStripper InputFile"); ifstream in(argv[1]); assure(in, argv[1]); string s; while(getline(in, s)) if(!stripHTMLTags(s).empty()) cout << s << endl; } ///:~
Listado 4.21. C03/HTMLStripper.cpp
Este ejemplo borrará incluso las etiquetas HTML que se
extienden a lo largo de varias líneas.[5] Esto se cumple gracias a la
bandera estática inTag
, que evalúa a cierto
si el principio de una etiqueta es encontrada, pero la
etiqueta de finalización correspondiente no es encontrada en
la misma línea. Todas la formas de
erase()
aparecen en la función
stripHTMLFlags()
.[6] La
versión de getline()
que usamos aquí es
una función (global) declarada en la cabecera de
string
y es útil porque guarda una
línea arbitrariamente larga en su argumento
string
. No necesita preocuparse de las
dimensiones de un arreglo cuando trabaja con
istream::
getline()
. Nótese
que este programa usa la función
replaceAll()
vista antes en este
capítulo. En el póximo capitulo, usaremos los flujos de cadena
para crear una solución más elegante.
[5] Para mantener la exposición simple, esta version no maneja etiquetas anidadas, como los comentarios.
[6] Es tentador usar aquí las matemáticas para evitar
algunas llamadas a erase()
, pero como en
algunos casos uno de los operandos es
string::
npos
(el
entero sin signo más grande posible), ocurre un desbordamiento
del entero y se cuelga el algoritmo.