用逗号分割字符串

时间:2020-05-14 00:51:48

标签: c++ c++17

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

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

    }

2 个答案:

答案 0 :(得分:2)

根据您的代码,我认为您误解了传递给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

这是完整的代码段:

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;,因为这被认为是不好的做法。

答案 1 :(得分:1)

因此,已经给出了很好的答案。

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

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

替代品

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