Удаление пустых элементов из вектора строк
Я пытаюсь сделать небольшую программу, которая обрабатывает файлы 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); }));