1

How can I read separate integers from the code below?

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

The input is like this: 1, 2, 3, 5 (separated by comma except the last integer).

Sample Input (ignore the line # part):

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

I need to read the integers one by one, and let's say increment and print them.

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
  • 1
    Related: [https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c](https://stackoverflow.com/questions/1120140/how-can-i-read-and-parse-csv-files-in-c) – drescherjm Jul 23 '20 at 22:09
  • You can find a *plethora* of examples by searching the internet for "C++ read comma separated example". Always search the internet before posting to Stack Overflow. – Thomas Matthews Jul 23 '20 at 22:21

3 Answers3

2

I make use of a handy utility to split a string into pieces using a char delimeter:

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

and then do something like this:

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
    }
 }
wcochran
  • 10,089
  • 6
  • 61
  • 69
2

By default, '\n' is the delimiter for std::getline(). You can specify ',' instead as the delimiter, eg:

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

Otherwise, you can use std::getline() with '\n' as the delimiter to read an entire line, and then use a separate std::istringstream to read values from that line, such as by using std::getline() with ',' as the delimiter, eg:

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

Alternatively, you can use streaming extraction via operator>>, eg:

string line;
if (getline(cin, line)) {
    istringstream iss(line);
    int num;
    while (iss >> num) {
        ...
        iss.ignore(); // skip terminating comma/whitespace
    }
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

I will show you several different approaches on how to tokenize a string:

Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.

Alternatives

  1. Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
  2. Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
  3. std::getline. Most used implementation. But actually a "misuse" and not so flexible
  4. Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.

Please see 4 examples in one piece of code.

#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;
}
A M
  • 14,694
  • 5
  • 19
  • 44