Удаление пустых элементов из вектора строк

Я пытаюсь сделать небольшую программу, которая обрабатывает файлы ini, для использования в более позднем проекте, сначала уменьшив ее размер после загрузки в память. Таким образом,

где vLine-вектор, содержащий содержимое файла

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

при печати vLine я останусь с пробелами, где когда-то существовала строка, начинающаяся с запятой, например

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

С помощью resize () появляется, чтобы удалить последний элемент из списка, а не удалить эти пустые участки. Та же проблема существует, когда я удаляю строки, содержащие только пробелы с помощью erase().

можно ли удалить эти пустые элементы при сохранении порядка vLine?

(извиняюсь за то, что не использовал итераторы в этом.)

3 ответов


это:

vLine[i].erase(); 

не стирать vLine[i] от вектора. Выражение vLine[i] возвращает ссылку на элемент в index i. Так что предположим, что vLine типа std::vector<std::string>, вызов функции erase() на самом деле называет string::erase() на элементе, не vector::erase() на вектор. Все, что вы делаете, это делаете этот конкретный элемент пустым.

что вы, вероятно, хотите что-то вроде этого:

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

это фактически удаляет элемент из вектора. Теперь это делает недействительными все текущие итераторы вектора, и индексы больше не будут правильными. Это ситуация, когда вам действительно нужно использовать итераторы.

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;
    }
}

но есть еще более простой способ сделать это: использовать стандартный алгоритм std::remove_if() С функтором затем вызовите 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());

если вы можете использовать компилятор C++11, то вы можете также использовать лямбда-выражения, чтобы быть еще более кратким.


проблема заключается в вашей логике удаления элементов. Когда вы сталкиваетесь с элементом в index i что вы хотите стереть, вы очищаете его значение, но вы не удаляете его из вектора.

стандартный и простой способ сделать то, что вы хотите сделать, это std::remove_if:

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

используйте идиому erase/remove -, предпочтительно с лямбдой из C++11:

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