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
You could use
getline
to read the stringquit
You could read
input
again, if it happens to be an empty string.You could call
cin.get();
after thecin >> 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 ofstr
in the string, ornpos
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 positionpos
and of lengthnpos
.
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:
- 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. - It seems you are mixing the what the input operator for
std::string
andstd::getline()
are doing: the input operator reads the first word after skipping leading spaces whilestd::getline()
read, well, a line (whether the line terminator can be specified as third argument). - 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:
- 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 thestd::stringstream
. - 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
How to Construct an Iso 8601 Datetime in C++
Ad Hoc Polymorphism and Heterogeneous Containers with Value Semantics
Difference Between String.H and Cstring
How to Force Inclusion of an Object File in a Static Library When Linking into Executable
How to Execute a Piece of Code Only Once
Why Use ++I Instead of I++ in Cases Where the Value Is Not Used Anywhere Else in the Statement
Access Violation on Static Initialization
Opencv: How to Visualize a Depth Image
Signal Handler Function in Multithreaded Environment
Default VS. Implicit Constructor in C++
Why Aren't Copy Constructors "Chained" Like Default Constructors and Destructors
How to Configure Cdb in Qt Creator
Does Std::Atomic<Std::String> Work Appropriately
Generating One Class Member Per Variadic Template Argument