This is making no sense to me. I do something to the code and it works only the first time. I then test it again and it goes back to not including the last element in the vector. I have no idea what I am doing wrong. Please help.
cout << "Enter a sentence: " << endl;
getline(cin, sentence);
for (auto x : sentence) // stores individual words in the vector
{
if (x == ' ')
{
myString.push_back(word);
cout << word << endl;
word = " ";
}
else
{
word = word + x;
}
}
for (auto elem : myString)
{
cout << elem << endl;
}
You are scanning the sentence one letter at a time, appending each letter to word until you encounter a space, and only then are you inserting the word into the vector. So, if the sentence does not end with a space, the last word won't be inserted into the vector.
There are a few different ways you can fix that:
check if word is not empty after the loop exits, and if not then insert it into the vector:
cout << "Enter a sentence: " << endl;
getline(cin, sentence);
for (auto x : sentence)
{
if (isspace(static_cast<unsigned char>(x))
{
if (!word.empty())
{
myString.push_back(word);
word = "";
}
}
else
{
word += x;
}
}
if (!word.empty())
{
myString.push_back(word);
}
for (const auto &elem : myString)
{
cout << elem << endl;
}
Scan for word boundaries yourself, such as with string::find_first_(not_)of():
cout << "Enter a sentence: " << endl;
getline(cin, sentence);
const char* wspace = " \f\n\r\t\v";
size_t start = 0, end;
while ((start = sentence.find_first_not_of(wspace, start)) != string::npos)
{
end = sentence.find_first_of(wspace, start + 1));
if (end == string::npos)
{
myString.push_back(sentence.substr(start));
break;
}
myString.push_back(sentence.substr(start, end-start));
start = end + 1;
}
for (const auto &elem : myString)
{
cout << elem << endl;
}
put the sentence into a std::istringstream and then use operator>> to extract complete whitespace-separate words from it. Let the standard library do all the heavy parsing for you:
cout << "Enter a sentence: " << endl;
getline(cin, sentence);
istringstream iss(sentence);
while (iss >> word)
{
myString.push_back(word);
}
for (const auto &elem : myString)
{
cout << elem << endl;
}
If there is no space after the last word, you are not adding it to your vector.
Related
I have a need to split the following string into their corresponding alpahbets and numbers
CH1000003
ABC000123
WXYZ10001
Results I want are
st1: CH
st2: 1000003
st1: ABC
st2: 000123
st1: WXYZ
st2: 10001
Now I do have a working code but the amount of code I have written seems a bit too much. There has to be an easy way. Perhaps somehow use regex in C++? Suggestions?
My code:
std::string idToCheckStr="CH1000003";
//find length of string
int strLength = idToCheckStr.length();
cout << "idToCheckStr: " << idToCheckStr <<endl;
cout << "strLength : " << strLength <<endl;
string::iterator it;
int index = 0;
for ( it = idToCheckStr.begin() ; it < idToCheckStr.end(); it++ ,index++)
{
//check where the numbers start in the string
if (std::isdigit(*it) != 0)
{
cout<< "FOUND NUMBER!" <<endl;
cout<< index << ": " << *it <<endl;
break;
}
cout<< index << ": " << *it <<endl;
}
std::string firstPartStr = idToCheckStr.substr (0,index);
cout << "firstPartStr: " << firstPartStr <<endl;
std::string secondPartStr = idToCheckStr.substr (index,strLength);
cout << "secondPartStr: " << secondPartStr <<endl;
OUTPUT:
idToCheckStr: CH1000003
strLength : 9
0: C
1: H
FOUND NUMBER!
2: 1
firstPartStr: CH
secondPartStr: 1000003
Thanks to igor.
size_t first_digit = idToCheckStr.find_first_of("0123456789");
cout << "first_digit: " << first_digit <<endl;
std::string str1 = idToCheckStr.substr (0,first_digit);
cout << "str1: " << str1 <<endl;
std::string str2 = idToCheckStr.substr (first_digit,idToCheckStr.length());
cout << "str2: " << str2 <<endl;
OUTPUT:
first_digit: 2
str1: CH
str2: 1000003
Here is one of the simple ways to handle your problem.
I find this more understandable for you.
string s = "CH1000003";
// cin >> s; if you waant to read the input
string st1 = "", st2 = "";
for(auto ch : s) {
if(isdigit(ch)) st2 += ch;
else if(isalpha(ch)) st1 += ch;
else {} // if you want something else
}
cout << "st1: " << st1 << endl;
cout << "st2: " << st2 << endl;
You could indeed use regular expressions for this:
The pattern would be ([A-Z]+)([0-9]+), i.e. any combination of 1 or more uppercase letters followed by any combination of 1 or more numbers. The parentheses allow you to capture those 2 groups to be able to access them later on.
std::regex_match(line, matches, pattern) takes an input line, and tries to match it against a pattern. If it can, stores the matches in a std::smatch array; where the first entry is always the whole match, and the successive ones are for each capturing group. If it can't, it just returns false.
Should you need to relax the regular expression, e.g. allowing white spaces before, after, or in the middle of the input string, you could do it easily just changing the pattern: \s*([A-Z]+)\s*([0-9]+)\s*.
[Demo]
#include <fmt/core.h>
#include <iostream> // cout
#include <regex> // regex_match, smatch
#include <string>
int main() {
std::string line{};
std::regex pattern{R"(([A-Z]+)([0-9]+))"};
while (std::getline(std::cin, line)) {
std::smatch matches{};
if (std::regex_match(line, matches, pattern)) {
std::cout << fmt::format("line = '{}', alphabets = '{}', numbers = '{}'\n",
matches[0].str(), matches[1].str(), matches[2].str());
}
}
}
// Outputs:
//
// line = 'CH1000003', alphabets = 'CH', numbers = '1000003'
// line = 'ABC000123', alphabets = 'ABC', numbers = '000123'
// line = 'WXYZ10001', alphabets = 'WXYZ', numbers = '10001'
The issue I'm having with this code stems from the last block of code for the get_words_beginning_s function.
/*
Name: xx
Date: xx
Purpose:Read text from file, count number of words, unique words, word frequency, & number of words that begin with letter 's'
*/
#include <iostream>
#include <fstream>
#include <string>
#include <set>
using namespace std;
multiset<string> display_and_load_words(string filename);
set<string> get_unique_words(multiset<string>& words);
set<string> get_words_beginning_s(multiset<string>& words);
int main() {
cout << "The Word Counter program\n\n";
string filename = "dickens.txt";
cout << "FILE TEXT: ";
//display_text(filename);
auto words = display_and_load_words(filename);
cout << "WORD COUNT: " << words.size() << endl << endl;
auto unique_words = get_unique_words(words);
auto words_beginning_s = get_words_beginning_s(words);
cout << unique_words.size() << " UNIQUE WORDS: ";
for (string word : unique_words) {
cout << word << ' ';
}
cout << endl << endl;
cout << "COUNT PER WORD: ";
for (string word : unique_words) {
cout << word << '=' << words.count(word) << ' ';
}
cout << endl << endl;
cout << "WORDS THAT BEGIN WITH 'S': ";
for (string word : words_beginning_s) {
cout << word << ' ';
}
cout << endl << endl;
}
multiset<string> display_and_load_words(string filename) {
multiset<string> words;
ifstream infile(filename);
if (infile) {
string word;
while (infile >> word) {
cout << word << ' ';
string new_word = "";
for (char c : word) {
if (c == '.' || c == ',') {
continue; // remove punctuation
}
else if (isupper(c)) {
new_word += tolower(c); // convert to lowercase
}
else {
new_word += c;
}
}
words.insert(new_word); // add word
}
cout << endl << endl;
infile.close();
}
return words;
}
set<string> get_unique_words(multiset<string>& words) {
set<string> unique_words;
for (string word : words) {
auto search = unique_words.find(word);
if (search == unique_words.end()) {
unique_words.insert(word);
}
}
return unique_words;
}
set<string> get_words_beginning_s(multiset<string>& words) {
set<string> words_beginning_s;
for (string word : words) {
auto search = words_beginning_s.find(word);
if (search == words_beginning_s.end()) {
for (int i = 0; i < words_beginning_s.size(); ++i) {
if (words_beginning_s[0] == 's') {
words_beginning_s.insert(word);
}
}
}
}
return words_beginning_s;
}
If working with set/multiset, how does one compare positional values within each separate word itself, rather the entire words? Example string in text file - "John goes to the store": Whereas normally a simple for loop can be used with the initial position to compare values and count number of times it appears (something like)-
for (int i = 0; i < words_beginning_s.length(); ++i) {
if (words_beginning_s[0] == 's') {
++s_word;
}
This does not work when using set/multiset. Pretty new to this, so sorry if this question seems dumb.
You can use the multisets member function lower_bound to get iterators to a range and then create a set from that range.
Example:
#include <iostream>
#include <set>
#include <string>
std::set<std::string> get_words_beginning_s(const std::multiset<std::string>& words) {
// create a set from the iterators you get from lower_bound("s") and lower_bound("t"):
return {words.lower_bound("s"), words.lower_bound("t")};
}
int main() {
std::multiset<std::string> words{
"foo", "slayer", "bar", "sepultura", "tesseract", "skinny puppy", "yello"
};
for(const std::string& word : get_words_beginning_s(words)) {
std::cout << word << '\n';
}
}
Output:
sepultura
skinny puppy
slayer
Here is a program where I enter a sentence and print it backward...
#include<iostream>
#include<string>
using namespace std;
int main(int argc, char* argv[]) {
string scrambleWords;
cout << "Please enter a sentence to scramble: ";
getline(cin, scrambleWords);
for (int print = scrambleWords.length() - 1; print >= 0; print--)
{
if (isspace(scrambleWords[print]))
{
for (unsigned int printIt = print + 1;
printIt < scrambleWords.length(); printIt++)
{
cout << scrambleWords[printIt];
if (isspace(scrambleWords[printIt]))
break;
}
}
}
for (unsigned int gotIt = 0; gotIt < scrambleWords.length(); gotIt++)
{
cout << scrambleWords[gotIt];
if (isspace(scrambleWords[gotIt]))
break;
}
cout << endl;
}
// OUTPUT
// Please enter a sentence: birds and bees
// beesand birds
// Press any key to continue . . .
As you can see there was no space between bees & birds, so how can I add the space in there?
The cleanest and easiest solution is to rely on the standard libraray:
// 1. Get your input string like you did
// 2. Save the sentence as vector of words:
stringstream sentence {scrambleWords};
vector<string> words;
copy(istream_iterator<string>{sentence},istream_iterator<string>{},
back_inserter(words));
// 3 a) Output the vector in reverse order
for (auto i = words.rbegin(); i != words.rend(); ++i)
cout << *i << " ";
// 3 b) or reverse the vector, then print it
reverse(words.begin(),words.end());
for (const auto& x : words)
cout << x << " ";
You may use something like (C++11 for auto): (http://ideone.com/mxOCM1)
void print_reverse(std::string s)
{
std::reverse(s.begin(), s.end());
for (auto it = s.begin(); it != s.end(); ) {
auto it2 = std::find(it, s.end(), ' ');
std::reverse(it, it2);
it = it2;
if (it != s.end()) {
++it;
}
}
std::cout << s << std::endl;
}
Add a space when you reached the end of the original input line:
if printIt == scrambleWords.length()-1
cout << " ";
Put this code in the inner for loop, after
if (isspace(scrambleWords[printIt]))
break;
Note that breaking out of a for loop is not going to win you any programming beauty contests.
int main()
{
int number_of_words = 0;
int prevnum = -1;
string previous = "";
string current;
while (cin >> current)
{
++number_of_words;
if (previous == current)
{
cout << "word number: " << number_of_words << "\n"
<< "Repeated Word: " << current << "\n";
previous = current;
}
else while (prevnum == number_of_words)
{
number_of_words = 0;
prevnum = 0;
break;
}
}
}
In this app, I'm trying to display repeated words and their position number within the text. When it finishes running the inputted statement, it keeps the number_of_words for the next input. I tried fixing this with the else while condition, at which the while loop would break.
What should I do differently?
Does the while loop run again after breaking or would i need to put this into another while loop that prompts the user on whether or not they are ready to type in some text?
*this is Ch. 3 so I'm guessing I should just move on but was curious
Try this:
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
int number_of_words;
string previous;
string current, input;
while (true)
{
previous = "";
number_of_words = 0;
cout << "\nWrite the data\n";
getline(std::cin, input);
stringstream ss;
ss << input;
while (ss >> current)
{
++number_of_words;
if (previous == current)
cout << "word number: " << number_of_words << "\n"
<< "Repeated Word: " << current << "\n";
previous = current;
}
}
}
I have used an stringstream variable to break every loop of input, so i could reset the counters.
the assignment is the basic "cin a full name" and then "retrieve First Middle Last" bit, where you create a program that asks the user to type in their full first name into a single string and the programs picks apart the name and outputs it organized seperately. this is what i wrote:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string name;
int index;
index = name.find(' ');
cin >> name;
cout << "First name: " << name.substr(0, index) << endl;
name = name.substr(index+1, name.length()-1);
index = name.find(' ');
cout << "Middle Name: " << name.substr(1, index) << endl;
name = name.substr(index+1, name.length()-1);
cout << "Last name: " << name;
return 0;
}
the code just wont seperate them right, and will not redefine 'name' correctly.
It always just bounces back to the beginning of the string.
any help for a newbie?
here's an example output:
Teenage Wonder Land
First name: Teenage
Middle Name: eenag
Last name: Teena
Process returned 0 (0x0) execution time : 7.942 s
Press any key to continue.
You wont' find anything before type your in console and sbustr should read from index 0
string name;
int index;
//index = name.find(' '); // comment out, name is empty, you won't find anything
cin >> name;
index = name.find(' '); // now you can find first space
cout << "Middle Name: " << name.substr(0, index) << endl;
// ^
Or just use std::stringstream
#include <sstream>
std::stringstream ss(name);
std::string token;
int i = 0;
while(ss >> token)
{
switch(i)
{
case 0:
std::cout << "First name: " << token << std::endl;
break;
case 1:
std::cout << "Middle name: " << token << std::endl;
break;
case 2:
std::cout << "Last name: " << token << std::endl;
break;
default:
break;
i++;
}
}
You clearly can't search for something in name before you assign it a value, which is what you're doing now:
string name;
int index;
index = name.find(' '); // No value assigned to name yet - nothing to search
cin >> name; // Now you're giving it a value (too late)
Instead, assign and then try to find a value:
string name;
int index;
cin >> name; // Assign a value first
index = name.find(' '); // Now try to find something in it
I think you should use std::getline to get the entire line of text at once. Currently you are only reading in the first word (>> operator will only extract text up to the next whitespace character).
std::string name;
if (std::getline(cin, name))
{
// extraction successful, "name" should contain entire line
}
Then, you can use one of the other answers in this question or continue with your own approach.
The extraction operator >> for istream will grab all non-whitespace characters in the buffer until it encounters a whispace.
So your input here:
Teenage Wonder Land
contains 3 whitespaces including the invisible newline at the end when you hit enter. From this you should be able to figure out what the following does:
cin >> name;
Hint: name doesn't contain the entire line you just entered.
#include <iostream>
#include <string>
using namespace std;
string getnext(const string &full, const string &delim, size_t &beg) {
size_t prev = beg;
beg = full.find(delim, beg);
if (beg != string::npos)
return full.substr(prev, beg-prev);
return full.substr(prev, full.length()-prev);
}
int main()
{
string name, temp, error = "NameError: Enter first, middle, last";
size_t index = 0;
getline(cin, name); //Get the full name
temp = getnext(name, " ", index); //Get first name
if (index == string::npos) {
cout << error;
return -1;
}
cout << "First name: " << temp << endl;
temp = getnext(name, " ", ++index); //Get middle name
if (index == string::npos) {
cout << error;
return -1;
}
cout << "Middle Name: " << temp << endl;
temp = getnext(name, " ", ++index); //Get last name
cout << "Last name: " << temp << endl;
return 0;
}