Use Getline and While Loop to Split a String

use getline and while loop to split a string

As Benjamin points out, you answered this question yourself in its title.

#include <sstream>
#include <vector>
#include <string>

int main() {
// inputs
std::string str("abc:def");
char split_char = ':';

// work
std::istringstream split(str);
std::vector<std::string> tokens;
for (std::string each; std::getline(split, each, split_char); tokens.push_back(each));

// now use `tokens`
}

Note that your tokens will still have the trailing/leading <space> characters. You may want to strip them off.

C++ split string by line

I'd like to use std::getline or std::string::find to go through the string.
below code demonstrates getline function

int doSegment(char *sentence)
{
std::stringstream ss(sentence);
std::string to;

if (sentence != NULL)
{
while(std::getline(ss,to,'\n')){
cout << to <<endl;
}
}

return 0;
}

Is there any easy way to read a line from a file, split the first text part into a string, then split the last number part into a float?

  • Grab the line into a string.
  • Get the position of the last separator.
  • Your text is a substring of the line until the position of the separator.
  • Your number is a substring of the line from the position of the separator. You'll need to convert it to double first (and you should check for errors).

[Demo]

#include <iostream>  // cout
#include <string> // find_last_of, getline, stod

int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
}

// Outputs
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// text = Fruit Basket, number = 2.49
// text = Cereal, number = 0.69
// text = Coffee, number = 0.5
// text = Tea, number = 0.75
//

A more robust solution taking into account @Dúthomhas' comments:

  • Trims the right hand side of the string before finding the last separator.
  • Catches std::stod exceptions.

This solution detects:

  • Blank lines.
  • Lines without texts.
  • Lines without numbers.
  • Incorrect number formats.

[Demo]

#include <boost/algorithm/string.hpp>
#include <fmt/core.h>
#include <iostream> // cout
#include <string> // find_last_of, getline, stod

int main()
{
std::string line{};
while (std::getline(std::cin, line))
{
try
{
boost::trim_right(line);
auto pos{line.find_last_of(' ')};
auto text{line.substr(0, pos)};
auto number{std::stod(line.substr(pos))};
std::cout << "text = " << text << ", number = " << number << "\n";
}
catch (const std::exception&)
{
std::cout << fmt::format("* Error: invalid line '{}'\n", line);
}
}
}

// Outputs:
//
// text = Plain Egg, number = 1.45
// text = Bacon and Egg, number = 2.45
// text = Muffin, number = 0.99
// text = French Toast, number = 1.99
// * Error: invalid line ''
// * Error: invalid line 'Fruit Basket'
// * Error: invalid line '0.75'
// * Error: invalid line 'Coffee blah'

std::getline not re-requesting user input in while loop

In the first iteration of the loop:

cin >> quit;

will read up to, but not including the newline character.

In the second iteration of the loop:

std::getline(std::cin, input);

will read that newline character, and hence read an empty string into input.

There are several ways to fix this

  1. You could use getline to read the string quit

  2. You could read input again, if it happens to be an empty string.

  3. You could call cin.get(); after the cin >> quit to clear the newline.

Parse (split) a string in C++ using string delimiter (standard C++)

You can use the std::string::find() function to find the position of your string delimiter, then use std::string::substr() to get a token.

Example:

std::string s = "scott>=tiger";
std::string delimiter = ">=";
std::string token = s.substr(0, s.find(delimiter)); // token is "scott"
  • The find(const string& str, size_t pos = 0) function returns the position of the first occurrence of str in the string, or npos if the string is not found.

  • The substr(size_t pos = 0, size_t n = npos) function returns a substring of the object, starting at position pos and of length npos.


If you have multiple delimiters, after you have extracted one token, you can remove it (delimiter included) to proceed with subsequent extractions (if you want to preserve the original string, just use s = s.substr(pos + delimiter.length());):

s.erase(0, s.find(delimiter) + delimiter.length());

This way you can easily loop to get each token.

Complete Example

std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";

size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
std::cout << token << std::endl;
s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;

Output:

scott
tiger
mushroom

Splitting a string by a character

Using vectors, strings and stringstream. A tad cumbersome but it does the trick.

#include <string>
#include <vector>
#include <sstream>

std::stringstream test("this_is_a_test_string");
std::string segment;
std::vector<std::string> seglist;

while(std::getline(test, segment, '_'))
{
seglist.push_back(segment);
}

Which results in a vector with the same contents as

std::vector<std::string> seglist{ "this", "is", "a", "test", "string" };

getline to split string manipulation error

There are a few blatant errors in your code:

  1. You need to always check your input after trying to read! You do that using the while-loop but you also need to verify that you actually successfully read the string first.
  2. It seems you are mixing the what the input operator for std::string and std::getline() are doing: the input operator reads the first word after skipping leading spaces while std::getline() read, well, a line (whether the line terminator can be specified as third argument).
  3. When reading fixed sized array you always need to make sure you do not read more than fits into this array! You may have heart about hackers exploiting software by using buffer overruns: assuming you'd actually indeed read a line first followed by splitting it into words you'd have created one of those exploitable programs! If you don't want to check before each word if there is enough space in the array, you'd use, e.g., a std::vector<std::string> (doing so also has a problem with hackers, namely that it opens up the program for a Denial of Service attack but although this is still a problem it is a somewhat lesser problem).

There are also a few smaller issues with your program, too:

  1. If you are only reading from a string stream, you should use std::istringstream as there is no need to also set up the writing part of the std::stringstream.
  2. The programs asks for "first name, middle name, and last name". I would read that specification to use, e.g., "John, F., Kennedy" but it seems you'd expect "John F. Kennedy". One reason I would expect that commas are to be used is that I don't have a middle name, i.e., I would enter "Dietmar, , Kühl".


Related Topics



Leave a reply



Submit