2011-10-07 10 views
7

Estoy intentando crear un pequeño programa que procese archivos INI, para usarlo en un proyecto posterior, primero reduciendo su tamaño una vez cargado en la memoria. Por lo tanto,Extracción de elementos vacíos de un vector de cadenas

donde vline es un vector que contiene el contenido del archivo

for (unsigned int i = 0; i < vLine.size(); i++) 
{ 
    if (!vLine[i].find(';', 0)) 
    { 
     vLine[i].erase(); 
    } 
} 

al imprimir vline, I le dejó con espacios donde una vez una línea que comienza con un punto y coma existido, tales como

1.  
2. property 
3. property 
4. 
5. property 

El uso del tamaño() parece eliminar el último elemento de la lista en lugar de eliminar estas partes vacías. El mismo problema existe cuando elimino líneas que solo contienen espacios en blanco con borrar().

¿Es posible eliminar estos elementos vacíos mientras se conserva el orden de vLine?

(disculpas para no usar iteradores en esta.)

+0

Re: (Disculpas por no usar iteradores en este.) - ¿Por qué no usar iteradores? –

+0

Falta de conocimiento sobre su uso correcto. Parece (¿parece?) Posible hacer esto sin ellos. – JGrey

+1

Puede eliminar las líneas del vector en lugar de simplemente borrar el contenido de la cadena (que es lo que 'vLine [i] .erase()' hace, no? Llamar a 'vLine.erase()' ya que eso borra del 'vector' Luego, vuelva a escribir el archivo. Una manera idiomática de hacerlo es C++ [borrar idioma] (http://en.wikipedia.org/wiki/Erase-remove_idiom), aunque le gustaría usar 'std :: remove_if 'from' 'para usar un condicional – birryree

Respuesta

8

Este:

vLine[i].erase(); 

no borra vLine[i] a partir del vector. La expresión vLine[i] devuelve una referencia al elemento en el índice i. Asumiendo que vLine es del tipo std::vector<std::string>, la llamada a la función erase() realmente llama a string::erase() en el elemento, no a vector::erase() en el vector. Todo lo que estás haciendo es dejar en blanco ese elemento en particular.

Lo que probablemente quiere decir algo como esto:

vLine.erase(vLine.begin() + i); 

En realidad, esto elimina el elemento del vector. Ahora, esto invalida todos los iteradores actuales al vector, y los índices ya no serán correctos. Esta es una situación en la que realmente necesita usar iteradores.

std::vector<std::string>::iterator i = vLine.begin(); 
while(i != vLine.end()) 
{ 
    if(i->find(';', 0) != std::string::npos) 
    { 
     i = vLine.erase(i); 
    } 
    else 
    { 
     ++i; 
    } 
} 

Pero hay una manera más fácil de hacer esto: usar el algoritmo estándar std::remove_if() con un funtor luego llamar vLine.erase().

struct HasSemicolon 
{ 
    bool operator()(const std::string& s) 
    { 
     return s.find(';', 0) != std::string::npos; 
    } 
}; 

// ... 

vLine.erase(std::remove_if(vLine.begin(), vLine.end(), HasSemicolon()), vLine.end()); 

Si puede utilizar un compilador de C++ 11, entonces se puede también utilizar expresiones lambda a ser aún más concisa.

+0

Muy obligado, In Silico. Me tomaré el tiempo para aprender iteradores y modificar mi aplicación en consecuencia. – JGrey

+0

¿Podría agregar un ejemplo usando C++ 11 lambdas? He estado intentando para resolverlo durante la mayor parte de una hora pero soy horrible al leer los documentos de C++. –

+0

@QPaysTaxes http://en.cppreference.com/w/cpp/algorithm/remove tiene un ejemplo con un lambda. – arekolek

4

Utilice el borrado/eliminar-idioma, preferiblemente con un lambda de C++ 11:

foo.erase(std::remove_if(foo.begin(), foo.end(), 
         [](const std::string& s) 
         { return s.find(';', 0); })); 
7

El problema es en la lógica para la eliminación de los elementos. Cuando se encuentra con un elemento en el índice i que desea borrar, borra su valor, pero no lo elimina del vector.

La forma estándar y simple de hacer lo que quiere hacer es std::remove_if:

vLine.erase(
    std::remove_if(
     vLine.begin(), 
     vLine.end(), 
     [](std::string const& s) { return s.size() != 0 && s.front() == ';'; }), 
    vLine.end()); 
Cuestiones relacionadas