Split string with space but only get first word - c++

I'm having problem to split the string with space as a delim. I have tried 2 of the proposed solution as in here:
Split a string in C++?
(using copy + istringstream and split method)
However, no matter what I did, the vector only get the first word (not the rest). When I use the split method, it's working with anything else (dot, comma, semi colon...) but not space.
Here is my current code, can you tell me what I get wrong? Or how I should try to approach the fix?
int main()
{
std::vector<std::string> textVector;
std::string textString;
std::cout << "Input command : ";
std::cin >> textString;
std::istringstream iss(textString);
std::copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), std::back_inserter(textVector));
for (int i = 0 ; i < textVector.size(); i++) {
std::cout << textVector[i];
}
return 0;
}
The runnable code: http://cpp.sh/8nzq

Reason is simple, std::cin >> textString only reads until first whitespace. So textString only contains the first word.
To read entire line, you should instead use: std::getline(std::cin, textString);

Related

Cannot push back a string into a vector of strings c++

I'm trying to create a program to separate a single line into a vector of strings separated by the blank spaces in said line, so turn:
foo bar
into
["foo", "bar"]
This is what I have so far:
string command;
string command_temp;
vector<string> command_seperated;
std::cin >> command;
for (int i = 0; i < command.length(); i++){
if (isspace(command[i])){
cout << "blankspace" << endl; command_seperated.push_back(command_temp);
command_temp.clear();
}
command_temp.push_back(command[i]);
for (int i = 0; i < command_temp.size(); i++){
cout << command_temp[i];
}
cout << endl;
}
for (int i = 0; i < command_seperated.size(); i++){
cout << command_seperated[i] << endl;
}
But, if I input "foo bar" when prompted, this just returns:
foo bar
f
fo
foo
Process returned 0 (0x0) execution time : 2.596 s
Press any key to continue
I assume the reason the last for loop isn't printing anything is that there's nothing in it and the push_back to command_seperated isn't working. I have no idea why.
I also don't know why the entire program seems to just stop working after the first blank space.
Using this to refresh my rudimentary C++ skills, so I would appreciate an explanation of why I'm wrong, rather than a more elegant alternative solution.
What you are seeing is normal behavior of operator>>, which is used for reading formatted input. It skips leading whitespace (if the skipws flag is enabled on the stream, which it normally is), then reads until EOF or whitespace is encountered. So, in your example, std::cin >> command receives only foo even though you entered foo bar. If you invoked std::cin >> command a 2nd time, you would receive bar.
To read a string that contains whitespace in it, use std::getline() instead:
std::getline(std::cin, command);
It does not skip leading whitespace, and reads until EOF or a linebreak (ie, from typing Enter) is encountered.
That being said, the parsing code you have shown can be greatly simplified if you use a std::istringstream with operator>> to parse the command, eg:
std::string command, token;
std::vector<std::string> command_seperated;
std::getline(std::cin, command);
std::istringstream iss(command);
while (iss >> token) {
command_seperated.push_back(token);
}
for (const auto &str : command_seperated){
cout << str << endl;
}

How to access individual word from c++ vector?

At the end of the program I output the contents of a vector, the strings were inputted from a text file. The entire vector is outputted, but how do I just output one word? I am asking this because I will later need to modify each string.
#include<iostream>
#include<fstream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
ifstream in;
string line, file_name;
vector <string> phrase;
int total_words, total_letters, total_chars;
cout << "PIG LATIN PROGRAM" << endl;
cout << "Which file are you accessing? : ";
cin >> file_name;
in.open(file_name);
if (in.fail()) cout << "\nFile not found!" << endl;
while(getline(in, line)) phrase.push_back(line);
for(int i = 0; i < phrase.size(); i++){
int limit = phrase.size() - 1;
while(i < limit && phrase[i] == phrase[i]){
i++;
}
cout << phrase[i];
}
You could start by splitting the line in phrase[i] at points there's whitespace:
std::istringstream iss{phrase[i]};
std::vector<std::string> words;
std::string word;
while (iss >> word)
words.push_back(std::move(word));
std::istringstream creates an input stream - a bit like cin - that contains the full line of text read from your file and stored in phrase[i]. If you then use >> word it will extract one whitespace-delimited word of text at a time.
Say your line/phrase[i] input contained "the blue socks were her favourites", it'll be split nicely into words. If there is also punctuation in the line, some of the strings in words will embed that punctuation, e.g. "world.". If you care about that, you can learn to use std::string member functions to search in and edit the strings.
In the case of punctuation you could use
std::erase(std::remove_if(word.begin(), word.end(), std::ispunct), word.end()) to remove it (further details/explanation).
phrase[i] == phrase[i]
Well, that's just redundant. This will always return true for a vector holding strings.
for(int i = 0; (...); i++){
while( (...) ){
i++;
}
}
You are modifying variable i twice in this a single for loop. Once in the third parameter of for, and once in an inner while loop. It's almost never a good idea.
What's happening here is that you set i=0, then immediately set it to point to the last element of a vector (as the second condition in while is always true).
Then you print this element to console, which is the last line of your text file.
What you want to do, is:
1. Load text file line by line into a vector.
2. Each element of vector will hold a single line.
3. Split each line into a vector of WORDS (space separated).
4. Work with the resulting vector.
Or pheraps:
1. Load file word by word at the beginning.
vector<string> words;
copy( istream_iterator<string>{YourFileStream}, istream_iterator<string>{}, back_inserter{words} ); // this will copy the content of file directly into vector, white-space-separated (no need for while loop to do it)
for ( auto i = phrase.begin(); i != phrase.end(); ++i ) // it's the proper c++ way of iterating over a vector. very similar, but variable i will point to every element of vector in order ( not just to the index of an element )
{
// do some work on *i. at least:
std::cout << *i; // dereference operator (*) is needed here, since i doesn't hold index of an element, it's a "pointer" to an element
}
If you need the first approach ( to differentiate between words in different lines ), here you can find some excellent ways to separate a string by any delimeter (space, for example): The most elegant way to iterate the words of a string

How can I split a getline() into array in c++

I have an input getline:
man,meal,moon;fat,food,feel;cat,coat,cook;love,leg,lunch
And I want to split this into an array when it sees a ;, it can store all values before the ; in an array.
For example:
array[0]=man,meal,moon
array[1]=fat,food,feel
And so on...
How can I do it? I tried many times but I failed!😒
Can anyone help?
Thanks in advance.
You can use std::stringstream and std::getline.
I also suggest that you use std::vector as it's resizeable.
In the example below, we get input line and store it into a std::string, then we create a std::stringstream to hold that data. And you can use std::getline with ; as delimiter to store the string data between the semicolon into the variable word as seen below, each "word" which is pushed back into a vector:
int main()
{
string line;
string word;
getline(cin, line);
stringstream ss(line);
vector<string> vec;
while (getline(ss, word, ';')) {
vec.emplace_back(word);
}
for (auto i : vec) // Use regular for loop if you can't use c++11/14
cout << i << '\n';
Alternatively, if you can't use std::vector:
string arr[256];
int count = 0;
while (getline(ss, word, ';') && count < 256) {
arr[count++] = word;
}
Live demo
Outputs:
man,meal,moon
fat,food,feel
cat,coat,cook
love,leg,lunch
I don't want to give you some code because you must be new at C++ and you have to learn by yourself but I can give an hint: use substring to store it into a vector of string.

When parsing a string using a string stream, it extracts a new line character

Description of the program : The program must read in a variable amount of words until a sentinel value is specified ("#" in this case). It stores the words in a vector array.
Problem : I use a getline to read in the string and parse the string with a stringstream. My problem is that the stringstream is not swallowing the new line character at the end of each line and is instead extracting it.
Some solutions I have thought of is to cut off the last character by creating a subset or checking if the next extracted word is a new line character, but I feel there is a better cost efficient solution such as changing the conditions for my loops.
I have included a minimized version of the overall code that reproduces the problem.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
const int MAX_LIST_SIZE = 1000;
string str;
string list[MAX_LIST_SIZE];
int numWords = 0;
// program starts here
getline(cin, str); // read innput
stringstream parse(str); // use stringstream to parse input
while(str != "#") // read in until sentinel value
{
while(!parse.fail()) // until all words are extracted from the line
{
parse >> list[numWords]; // store words
numWords++;
}
getline(cin,str); // get next line
parse.clear();
parse.str(str);
}
// print number of words
cout << "Number of words : " << numWords << endl;
}
And a set of test input data that will produce the problem
Input:
apples oranges mangos
bananas
pineapples strawberries
Output:
Number of words : 9
Expected Output:
Number of words : 6
I would appreciate any suggestions on how to deal with this problem in an efficient manner.
Your logic for parsing out the stream isn't quite correct. fail() only becomes true after a >> operation fails, so you'll doing an extra increment each time. For example:
while(!parse.fail())
{
parse >> list[numWords]; // fails
numWords++; // increment numWords anyway
} // THEN check !fail(), but we incremented already!
All of these operations have returns that you should check as you go to avoid this problem:
while (getline(cin, str)) { // fails if no more lines in cin
if (str != "#") { // doesn't need to be a while
stringstream parse(str);
while (parse >> list[numWords]) { // fails if no more words
++numWords; // *only* increment if we got one!
}
}
}
Even better would be to not use an array at all for the list of words:
std::vector<std::string> words;
Which can be used in the inner loop:
std::string temp;
while (parse >> temp) {
words.push_back(temp);
}
The increment on numwords happens one more time than you intend at the end of each line. Use a std::vector< std::string > for your list. Then you can use list.size().

Parsing and adding string to vector

I have the following string "0 1 2 3 4 "(There is a space at the end of the string). Which i would like to split and add to a vector of string. When i use a loop and a stringstream, the program loops itself into a infinity loop with the last number 4. It does not want to stop.
How can I split the following and add to a vector of strings at the same time.
Please advcie.
stringstream ss(currentLine);
for(int i=0;i<strlen(currentLine.c_str());i++){
ss>>strCode;
strLevel.push_back(strCode);
}
std::ifstream infile(filename.c_str());
std::string line;
if (infile.is_open())
{
std::cout << "Well done! File opened successfully." << std::endl;
while (std::getline(infile, line))
{
std::istringstream iss(line);
std::vector<std::string> tokens { std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>() };
for (auto const &token : tokens)
if (!token.compare("your_value"))
// Do something....
}
}
First of all, we read a line just by using std::istringstream iss(line), then we split words according to the whitespaces and store them inside the tokens vector.
Update: thanks to Nawaz for improvement suggestions (see comments).
stringstream ss(currentLine);
while ( ss >> strCode )
strLevel.push_back(strCode);
That should be enough.