【问题标题】:Splitting a String up by comma用逗号分割字符串
【发布时间】:2020-08-30 09:33:56
【问题描述】:

我试图用逗号分割一个字符串并填充一个向量。当前代码适用于第一个索引,但是,对于下一次迭代,迭代器会忽略逗号,但会理解之后的那个。谁能告诉我这是为什么?

    getline(file,last_line);
    string Last_l = string(last_line);
    cout<< "String Lastline worked "<< Last_l <<endl;
    int end = 0;
    int start = 0;
    vector<string> linetest{};

    for(char &ii : Last_l){
        if( ii != ','){
            end++;
        }
        else{
            linetest.push_back(Last_l.substr(start,end));
//            Disp(linetest);
            cout<< Last_l.substr(start,end) <<endl;
            end++;
            start = end;
        }

    }

【问题讨论】:

标签: c++ c++17


【解决方案1】:

根据您的代码,我认为您误解了传递给substr 的参数。请注意,第二个索引是第一个参数之后的字符数不是子字符串的结束索引。

考虑到这一点,在 else 条件下,而不是:

end++;  // increment end index
start = end;  // reset start index

您需要执行以下操作:

start = end + 1;  // reset start index
end = 0;  // reset count of chars

另外,不要忘记在循环结束后添加最后一个逗号后剩余的额外字符串:

linetest.push_back(Last_l.substr(start + end));  // all the remaining chars

这是完整的 sn-p:

for(char &ii : Last_l){
        if( ii != ','){
            end++;
        }
        else{
            linetest.push_back(Last_l.substr(start,end));
            start = end + 1;
            end = 0;
        }
}

linetest.push_back(Last_l.substr(start + end));

还有一个工作的demo

如果您将 end 重命名为 count,这将更有意义。

另外,请避免使用using namespace std;,因为这被认为是不好的做法。

【讨论】:

    【解决方案2】:

    所以,已经给出了一个很好的答案。

    我想展示一些替代解决方案

    将字符串拆分为标记是一项非常古老的任务。有许多可用的解决方案。都有不同的属性。有些难以理解,有些难以开发,有些更复杂、更慢或更快或更灵活或不灵活。

    替代品

    1. 像您的一样手工制作,可能难以开发且容易出错。看你的问题。 . .
    2. 使用旧式std::strtok 函数。也许不安全。也许不应该再使用了
    3. std::getline。最常用的实现。但实际上是一种“误用”,并不那么灵活
    4. 使用专门为此目的开发的专用现代功能,最灵活且最适合 STL 环境和算法环境。但速度较慢

    请在一段代码中查看 4 个示例。

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <regex>
    #include <algorithm>
    #include <iterator>
    #include <cstring>
    #include <forward_list>
    #include <deque>
    
    using Container = std::vector<std::string>;
    std::regex delimiter{ "," };
    
    
    int main() {
    
        // Some function to print the contents of an STL container
        auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
            std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
    
        // Example 1:   Handcrafted -------------------------------------------------------------------------
        {
            // Our string that we want to split
            std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
            Container c{};
    
            // Search for comma, then take the part and add to the result
            for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
    
                // So, if there is a comma or the end of the string
                if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
    
                    // Copy substring
                    c.push_back(stringToSplit.substr(startpos, i - startpos));
                    startpos = i + 1;
                }
            }
            print(c);
        }
    
        // Example 2:   Using very old strtok function ----------------------------------------------------------
        {
            // Our string that we want to split
            std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
            Container c{};
    
            // Split string into parts in a simple for loop
    #pragma warning(suppress : 4996)
            for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
                c.push_back(token);
            }
    
            print(c);
        }
    
        // Example 3:   Very often used std::getline with additional istringstream ------------------------------------------------
        {
            // Our string that we want to split
            std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
            Container c{};
    
            // Put string in an std::istringstream
            std::istringstream iss{ stringToSplit };
    
            // Extract string parts in simple for loop
            for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
                ;
    
            print(c);
        }
    
        // Example 4:   Most flexible iterator solution  ------------------------------------------------
    
        {
            // Our string that we want to split
            std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
    
    
            Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
            //
            // Everything done already with range constructor. No additional code needed.
            //
    
            print(c);
    
    
            // Works also with other containers in the same way
            std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
    
            print(c2);
    
            // And works with algorithms
            std::deque<std::string> c3{};
            std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
    
            print(c3);
        }
        return 0;
    }
    
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多