So I have an arbitrarily long string that I take as an input from the user and I want to tokenise it and store it in a vector<std::string>. here is the code that I am using (which maybe inspired from my C background):
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
#include <sstream>
#include <string.h>
using namespace std;
int main()
{
string input;
cout << "Input a \' \' or \',\' or \'\\r\' separated string: ";
cin >> input;
vector<string> tokens;
char *str = new char[input.length() + 1];
strcpy(str, input.c_str());
char * pch;
pch = strtok(str, " , \r");
while (pch != NULL)
{
tokens.push_back(pch);
pch = strtok(NULL, " , \r");
}
for (vector<string>::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
cout << *i << ' ';
return 0;
}
However, this only tokenizes the first word and nothing after that, like viz:
Input a ' ' or ',' or '\r' string: hello, world I am C.
hello
What am I doing wrong and what would be the correct way to do it without using third party library?
Regards.
This is, sadly, a quite common pitfall. Many introductory courses and books on C++ teach you to accept interactive input like this:
cin >> input;
Many introductory simple exercises typically prompt for a single value of some sort, and that works fine, for that use case.
Unfortunately, these books don't fully explain what >> actually does, and what it does, really, is strip whitespace from input, and only process input up until the next whitespace. Even when input is a string.
So, when you enter a whole line of text, only the first word is read into input. The solution is to use the right tool, for the right job: std::getline(), which reads a single line of text, and puts it into a single string variable:
getline(cin, input);
Related
I am a beginner in c++ and I want to enter a string as character by character into an array , so that I can implement a reverse function .. However unlike C when the enter is hit a '\n' is not insterted in the stream.. how can I stop data from being entered ?
my code is :
#include<iostream>
#include<array>
#define SIZE 100
using namespace std;
char *reverse(char *s)
{
array<char, SIZE>b;
int c=0;
for(int i =(SIZE-1);i>=0;i--){
b[i] = s[c];
c++;
}
return s;
}
int main()
{
cout<<"Please insert a string"<<endl;
char a[SIZE];
int i=0;
do{
cin>>a[i];
i++;
}while(a[i-1]!= '\0');
reverse(a);
return 0;
}
When you read character by character, it really reads characters, and newline is considered a white-space character.
Also the array will never be terminated as a C-style string, that's not how reading characters work. That means your loop condition is wrong.
To begin with I suggest you start using std::string for your strings. You can still read character by character. To continue you need to actually check what characters you read, and end reading once you read a newline.
Lastly, your reverse function does not work. First of all the loop itself is wrong, secondly you return the pointer to the original string, not the "reversed" array.
To help you with the reading it could be done something like
std::string str;
while (true)
{
char ch;
std::cin >> ch;
if (ch == '\n')
{
break; // End loop
}
str += ch; // Append character to string
}
Do note that not much of this is really needed as shown in the answer by Stack Danny. Even my code above could be simplified while still reading one character at a time.
Since you tagged your question as C++ (and not C) why not actually solve it with the modern C++ headers (that do exactly what you want, are tested, save and work really fast (rather than own functions))?
#include <string>
#include <algorithm>
#include <iostream>
int main(){
std::string str;
std::cout << "Enter a string: ";
std::getline(std::cin, str);
std::reverse(str.begin(), str.end());
std::cout << str << std::endl;
return 0;
}
output:
Enter a string: Hello Test 4321
1234 tseT olleH
I am trying to write a function to split the string and return it like a substring. The code is worked. I just meet a question: how to remove double quotation marks and comma in the output when I input space for the first string? Any help is appreciated! Thank you!
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <ctype.h>
using namespace std;
vector<string> split(string targer, string delimiter);
int main()
{
string s, delimiter;
vector<string> tokens;
cout << "Enter string to split:" << endl;
getline (cin,s);
cout << "Enter delimiter string:" << endl;
getline (cin,delimiter);
tokens = split(s, delimiter);
cout << "The substrings are: ";
for(int i = 0; i < tokens.size() - 1; i++)
{
if (tokens[i].length() != 0){
cout << "\"" << tokens[i] << "\"" << "," << " ";
}
}
if (tokens.size() != 0)
{
cout << "\"" << tokens[tokens.size() - 1] << "\"";
}
cout<<endl;
return 0;
}
vector<string> split(string target, string delimiter){
stringstream ss(target);
string item;
vector<string> tokens;
while (getline(ss, item, delimiter.at(0))) {
tokens.push_back(item);
}
return tokens;
}
Your issue is not "how to remove double quotation marks and comma in the output when I input space for the first string".
Your issue is correctly splitting the string, so that a quoted string that contains spaces gets correctly extracted as a single string.
The simple methods offered by the I/O library to parse input up until the next delimiting character is not sufficient in order to be able to handle splitting a string, in this manner, on its own. They don't know anything about quotes. You will have to do the job yourself:
Scan the input string one at a time, using the following logic.
If the current character is a delimiting character, continue to the next character.
If the current character is a quote, then continue to scan until the next quote character is seen, then extract everything between the quotes into a single word.
Otherwise, continue to scan until the next delimiting character is seen, and then extract everything until that point into a single word.
This is a basic high-level outline of a typical splitting algorithm. You will end up with individual extracted words, with quoted content as a single word. You can take this high-level overview, and rewrite it as a lower-level, more detailed algorithm, then explain it to your rubber duck. After your rubber duck agrees that your detailed algorithm will work, you can then translate it directly into code.
Once you have implemented this correctly, you can refine this further to allow the quote characters themselves to be included in a quoted word. Typically that's done by using either two consecutive quotes, in a row, or a backslash "escape" character.
I'm supposed to force the user to input a number then a space then a string and if the format was wrong, I should terminate the program. When I used the cin, the compiler ignored the space and considered the first character of the string to be the one he should check to make sure that the user inputs a space and since the first character is always not a space he terminates.
What should I do ?!
I assume by "when I used the cin" you mean with the >> operator. Reading from an istream with >> is a formatted input function which means the input is pre-formatted for you, one of the effects is skipping over whitespace by default.
There are several ways to solve your problem, including reading a single character at a time (using an unformatted input function such as std::istream::get) or reading a line at a time and parsing the line.
Alternatively, you can turn off skipping of whitespace characters with the noskipws manipulator:
#include <iostream>
#include <string>
int main()
{
int num;
char c;
std::string str;
if (std::cin >> std::noskipws >> num >> c >> str && c == ' ')
std::cout << "ok" << std::endl;
else
std::cout << "Failed" << std::endl;
}
Use std::getline. If you require further help, make sure to post a code sample which demonstrates the problem, otherwise you won't get specific answers.
Example:
#include <string>
#include <iostream>
int main()
{
std::string input;
std::cout << "Please enter a number and a string, separated by a space:";
std::getline(std::cin, input);
// Code to validate input
}
I am using getline() function to get ride of special characters and punctuation in a sentence, so that when i display the words contained in the sentence, it does not have any other character beside a-z (or A-Z). The problem is that it gets long, and I don't think it is really efficient. I would like to know if I can do it in a efficient way. I am using Dev-C++, the code below is in C++. Thanks for your help.
#include <string>
#include <iostream>
#include <ctype.h>
#include <sstream>
using namespace std;
int main()
{
int i=0;
char y;
string prose, word, word1, word2;
cout << "Enter a sentence: ";
getline(cin, prose);
string mot;
stringstream ss(prose);
y=prose[i++];
if (y=' ') // if character space is encoutered...
cout<<endl << "list of words in the prose " << endl;
cout << "---------------------------"<<endl;
while(getline(ss, word, y)) //remove the space...
{
stringstream ss1(word);
while(getline(ss1, word1, ',')) //remove the comma...
{
stringstream ss2(word1); //remove the period
while(getline(ss2, word2, '.'))
cout<< word2 <<endl; //and display just the word without space, comma or period.
}
}
cout<<'\n';
system ("Pause");
return 0;
}
#############################output
Enter a sentence: What? When i say: "Nicole, bring me my slippers, and give me m
y night-cap," is that prose?
list of words in the prose
What?
When
i
say:
"Nicole
bring
me
my
slippers
and
give
me
my
night-cap
"
is
that
prose?
Press any key to continue . . .
Use std::remove_if():
std::string s(":;[{abcd 8239234");
s.erase(std::remove_if(s.begin(),
s.end(),
[](const char c) { return !isalpha(c); }),
s.end());
If you do not have a C++11 compiler, define a predicate instead of using a lambda (online demo http://ideone.com/NvhKq).
i have a little problem on writing the string into a file,
How can i write the string into the file and able to view it as ascii text?
because i am able to do that when i set the default value for str but not when i enter a str data
Thanks.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
fstream out("G://Test.txt");
if(!out) {
cout << "Cannot open output file.\n";
return 1;
}
char str[200];
cout << "Enter Customers data seperate by tab\n";
cin >> str;
cin.ignore();
out.write(str, strlen(str));
out.seekp(0 ,ios::end);
out.close();
return 0;
}
Please use std::string:
#include <string>
std::string str;
std::getline(cin, str);
cout << str;
I'm not sure what the exact problem in your case was, but >> only reads up to the first separator (which is whitespace); getline will read the entire line.
Just note that >> operator will read 1 word.
std::string word;
std::cin >> word; // reads one space seporated word.
// Ignores any initial space. Then read
// into 'word' all character upto (but not including)
// the first space character (the space is gone.
// Note. Space => White Space (' ', '\t', '\v' etc...)
You're working at the wrong level of abstraction. Also, there is no need to seekp to the end of the file before closing the file.
You want to read a string and write a string. As Pavel Minaev has said, this is directly supported via std::string and std::fstream:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ofstream out("G:\\Test.txt");
if(!out) {
std::cout << "Cannot open output file.\n";
return 1;
}
std::cout << "Enter Customer's data seperated by tab\n";
std::string buffer;
std::getline(std::cin, buffer);
out << buffer;
return 0;
}
If you want to write C, use C. Otherwise, take advantage of the language you're using.
I can't believe no one found the problem. The problem was that you were using strlen on a string that wasn't terminated with a null character. strlen will keep iterating until it finds a zero-byte, and an incorrect string length might be returned (or the program might crash - it's Undefined Behavior, who knows?).
The answer is to zero-initialize your string:
char str[200] = {0};
Supplying your own string as the value of str works because those in-memory strings are null-terminated.