字符串的转换向量:根据先前的值跳过元素

时间:2019-05-17 15:54:04

标签: c++ c++11 lambda stl

我需要将字符串向量转换为小写字母,但我需要保留文件名的 case 。它们由以前的字符串标记“ file”或“ out”标识。

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>

template <class T>
void print(const T& v) {
    std::copy(v.begin(), v.end(), 
            std::ostream_iterator<typename T::value_type>(std::cout, "\n"));
}

std::string lowercase(const std::string& s) 
{
    std::string result(s);
    std::transform(result.begin(), result.end(), result.begin(), ::tolower);
    return result;
}

int main() {

    std::vector<std::string> tokens {"Col1", "Col2", "File", "FileIn.dat", "Out", "FileOut.dat"};
    std::transform(tokens.begin(), tokens.end(), tokens.begin(), lowercase);

    // how to replace lowercase() with a lambda that will take the previous
    // element into account while converting an element into lowercase
    print(tokens);

    return 0;
}

在上面的代码中结果应该是

{"col1", "col2", "file", "FileIn.dat", "out", "FileOut.dat"};

保留“ file”和“ out”之后的字符串的大小写。

是否可以使用std::transformlambda函数来做到这一点?

3 个答案:

答案 0 :(得分:2)

是的。您可以像这样使用捕获的lambda:

bool is_filename = false;
std::transform(tokens.begin(), tokens.end(), tokens.begin(),
    [&is_filename] (auto &s) {
        if (is_filename)
            is_filename = false;
        else  
        {
            s = lowercase (s);
            is_filename = s == "file" || s == "out";
        }
        return s;
    });

输出:

col1
col2
file
FileIn.dat
out
FileOut.dat

Live demo

答案 1 :(得分:2)

是的。您可以捕获一些状态,然后根据看到的内容进行设置。但是,您不应使用std::transform,因为它不能保证按顺序遍历。您必须使用std::for_each

int main() {

    std::vector<std::string> tokens {"Col1", "Col2", "File", "FileIn.dat", "Out", "FileOut.dat"};

    bool toggle = true;
    auto lowercase = [&toggle](std::string & s) 
    {
        if (toggle)
        {
            std::transform(s.begin(), s.end(), s.begin(), ::tolower);
        }

        toggle = (s == "file") || (s == "out");
    }

    std::for_each(tokens.begin(), tokens.end(), tokens.begin(), lowercase);
    print(tokens);

    return 0;
}

答案 2 :(得分:1)

  

是否可以使用std :: transform和lambda函数来做到这一点?

std::transform不保证按顺序应用操作员。 因此,如果我们需要对这个问题应用std::transform,则最好使用二进制运算符的重载:

Live Demo

std::vector<std::string> tokens {"Col1", "Col2", "File", "FileIn.dat", "Out", "FileOut.dat"};

{    
    // The first element must not be file name.
    tokens[0] = lowercase(tokens[0]);

    std::vector<std::string> dummy;        
    std::transform(
        std::next(tokens.begin()), tokens.end(), tokens.begin(),
        std::back_inserter(dummy),
        [](auto& target, const auto& prev)
        {            
            const auto prevLower  = lowercase(prev);
            const auto isFileName = (prevLower == "file") || (prevLower == "out");

            if(!isFileName){
                target = lowercase(target);
            }

            return "";
        });
}

print(tokens);