【问题标题】:Read comma separated integers from getline()从 getline() 读取逗号分隔的整数
【发布时间】:2020-07-23 22:06:37
【问题描述】:

如何从下面的代码中读取单独的整数?

while (getline(cin, line)) {
    // for each integer in line do something.....
    // myVector.push_back(each integer)
}

输入是这样的:1, 2, 3, 5(除最后一个整数外,用逗号分隔)。

示例输入(忽略行号部分):

 line1: 1, 2, 3, 4, 5
 line2: 6, 7, 8, 9, 10
 line3: 3, 3, 3, 3, 3
 /// and so on...

我需要一个一个地读取整数,让我们说递增并打印它们。

【问题讨论】:

标签: c++ c++11


【解决方案1】:

我利用一个方便的实用程序使用字符分隔符将字符串拆分为多个片段:

std::vector<std::string> split(const std::string& str, char delim) {
    std::vector<std::string> strings;
    size_t start;
    size_t end = 0;
    while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
        end = str.find(delim, start);
        strings.push_back(str.substr(start, end - start));
    }
    return strings;
}

然后做这样的事情:

while (getline(cin, line)) {
    std::vector<std::string> strings = split(line, ',');
    for (const auto& str : strings) {
        const int i = std::stoi(str);
        // do something w i
    }
 }

【讨论】:

    【解决方案2】:

    默认情况下,'\n'std::getline() 的分隔符。您可以指定',' 作为分隔符,例如:

    string value;
    while (getline(cin, value, ',')) {
        int num = stoi(value);
        ...
    }
    

    否则,您可以使用std::getline()'\n' 作为分隔符来读取整行,然后使用单独的std::istringstream 从该行读取值,例如使用std::getline()','作为分隔符,例如:

    string line;
    if (getline(cin, line)) {
        istringstream iss(line);
        string value;
        while (getline(iss, value, ',')) {
            int num = stoi(value);
            ...
        }
    }
    

    或者,您可以通过operator&gt;&gt; 使用流式提取,例如:

    string line;
    if (getline(cin, line)) {
        istringstream iss(line);
        int num;
        while (iss >> num) {
            ...
            iss.ignore(); // skip terminating comma/whitespace
        }
    }
    

    【讨论】:

      【解决方案3】:

      我将向您展示几种不同的方法来标记字符串:

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

      替代品

      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
        • 2016-06-18
        • 1970-01-01
        • 2020-04-04
        • 1970-01-01
        • 2016-09-28
        • 2023-03-15
        • 1970-01-01
        相关资源
        最近更新 更多