简体   繁体   English

从字符串向量中删除空元素

[英]Removing Empty Elements from a Vector of Strings

I'm attempting to make a small program that processes INI files, for use in a later project, first by reducing its size once loaded into memory.我正在尝试制作一个处理 INI 文件的小程序,以便在以后的项目中使用,首先通过在加载到 memory 后减小其大小。 Thus,因此,

where vLine is a vector containing the file contents其中 vLine 是包含文件内容的向量

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

Upon printing vLine, I'll be left with spaces where once a line beginning with a semi-colon existed, such as在打印 vLine 时,我会留下空格,其中曾经存在以分号开头的行,例如

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

Using resize() appears to remove the last element from the list rather than remove these empty portions.使用 resize() 似乎是从列表中删除最后一个元素,而不是删除这些空白部分。 The same problem exists where I remove lines that only contain whitespace with erase().同样的问题存在于我使用erase() 删除仅包含空格的行。

Is it possible to remove these empty elements while preserving the order of vLine?是否可以在保留 vLine 顺序的同时删除这些空元素?

(Apologies for not using iterators in this.) (很抱歉在此不使用迭代器。)

This:这个:

vLine[i].erase(); 

does not erase vLine[i] from the vector.不会从向量中删除vLine[i] The expression vLine[i] returns a reference to the element at index i .表达式vLine[i]返回对索引i处元素的引用。 So assuming that vLine is of type std::vector<std::string> , the function call erase() actually calls string::erase() on the element, not vector::erase() on the vector.因此,假设vLine的类型为std::vector<std::string> ,则 function 调用erase()实际上是在元素上调用string::erase() ,而不是在向量上调用vector::erase() All you're doing is making that particular element blank.您所做的就是使该特定元素变为空白。

What you probably want is something like this:你可能想要的是这样的:

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

This actually removes the element from the vector.这实际上从向量中删除了元素。 Now, this does invalidate all current iterators to the vector, and the indices won't be right anymore.现在,这确实使向量的所有当前迭代器无效,并且索引将不再正确。 This is a situation where you really need to use iterators.这是您真正需要使用迭代器的情况。

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

But there's an even easier way to do this: use the standard algorithm std::remove_if() with a functor then call vLine.erase() .但是有一种更简单的方法可以做到这一点:使用标准算法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());

If you can use a C++11 compiler, then you can also use lambda expressions to be even more concise.如果您可以使用 C++11 编译器,那么您也可以使用 lambda 表达式来更加简洁。

The problem is in your logic for removing the elements.问题在于您删除元素的逻辑。 When you come across an element at index i that you want to erase, you clear its value, but you do not remove it from the vector.当您遇到要擦除的索引i处的元素时,您会清除其值,但不会将其从向量中删除。

The standard and simple way to do what you want to do is std::remove_if :做你想做的事情的标准和简单的方法是std::remove_if

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

Use the erase/remove-idiom, preferably with a lambda from C++11:使用擦除/删除习语,最好使用来自 C++11 的 lambda:

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

With C++20 you can use std::erase which is equivalent to the erase-remove idiom.使用 C++20,您可以使用std::erase ,它等效于擦除删除习语。

std::erase_if(vLine, [](auto&& str){
    return str.find(';', 0) != std::string::npos;
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM