How can I transform a user-defined string into an integer - c++

I basically ask a user to input a string, let's say they input "ABC" or"DEF"
Then, I want to set a certain integer = 1 if ABC is entered and 2 if DEF is entered.
If anything else is entered, then I want it to say invalid value.
So at the end, I'll have the integer i assigned to 1 or 2 if a valid value was entered.
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string input = "";
// How to get a string/sentence with spaces
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
cout << ".\n" << "You entered: " << input << endl << endl;
int m
if(input = ABC)
return 0;
}

Very easy:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, int> const v { { "ABC", 1 }, { "DEF", 2 } };
for (std::string line; std::getline(std::cin, line); )
{
auto it = v.find(line);
if (it == v.end())
{
std::cout << "Input '" << line << "' is invalid.\n";
}
else
{
std::cout << "Your input value: " << it->second << "\n";
}
}
}

Your English spec:
” set a certain integer = 1 if ABC is entered and 2 if DEF is entered […] if anything else is entered, then I want it to say invalid value.
Expressed in C++:
if( s == "ABC" ) { x = 1; }
else if( s == "DEF" ) { x = 2; }
else { cout << "Invalid value." << endl; }
If neither of the specified possibilites is true, i.e. in the case of outputting "Invalid value.", then x keeps the value it had, which is how I interpret the word “set”.
At a higher level of abstraction, it seems like you want the user to specify one of two strings, namely “ABC” or “DEF”, which you want to have available as an integer id after the input operation.
Then there are two main possibilities:
you want the id to indicate also the case where the user specified some other string, e.g. a common value for this, or
you want the input operation to only return control when the user has inputted one of the two valid strings.
The last case effectively means that input operation must loop or logically fail. Logical failure can be expressed as an exception, or e.g. by calling std::terminate.
So as you see there is a range of possibilities here, i.e. above the simple “how do I translate this English to C++” the desired functionality is a bit under-specified.

#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
Second solution if you want your m const. This assumes your compiler supports lambda functions:
#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
const int m = [&]() {
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end())
return it->second;
}
}();
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
If your compiler does not support the above map initialization then you can use instead:
#include <iostream>
#include <map>
#include <string>
using namespace std;
std::map<std::string, int> initializeMap() {
std::map<std::string, int> map;
map["ABC"] = 1;
map["DEF"] = 2;
// add whatever else here
return map;
}
int main()
{
const std::map<std::string, int> lookupTable = initializeMap();
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}

Related

How to convert a string to a dictionary of letters?

I need to convert letters into a dictionary of characters.
Here's an example:
letter
l: 1
e: 2
t: 2
r: 1
I did some research and found this helpful answer, but that was using getline() and separating words by spaces. Since I am trying to split by character I don't think I can use getline() since '' isn't a valid split character. I could convert to a char* array but I wasn't sure where that would get me.
This is fairly easy in other languages so I thought it wouldn't be too bad in C++. I was hoping there would be something like a my_map[key]++ or something. In Go I would write this as
// Word map of string: int values
var wordMap = make(map[string]int)
// For each letter, add to that key
for i := 0; i < len(word); i++ {
wordMap[string(word[i])]++
}
// In the end you have a map of each letter.
How could I apply this in C++?
How could I apply this in C++?
It could look rather similar to your Go code.
// Word map of char: int values
// (strings would be overkill, since you know they are a single character)
auto wordMap = std::map<char,int>{};
// For each letter, add to that key
for ( char c : word )
wordMap[c]++;
}
Here is the unicode version of Drew Dormann's answer:
#include <locale>
#include <codecvt>
std::string word = "some unicode: こんにちは世界";
std::map<char32_t, uint> wordMap;
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
for (auto c : converter.from_bytes(word)) {
wordMap[c]++;
}
for (const auto [c, v] : wordMap) {
std::cout << converter.to_bytes(c) << " : " << v << std::endl;
}
I wrote an article about this which can be checked out here. Below i have given 2 versions of the program. Version 1 keeps track of the character count in alphabetical order. But sometimes(in case) you want the character count in insertion order for which you can use Version 2.
Version 1: Get character count in ͟a͟l͟p͟h͟a͟b͟e͟t͟i͟c͟a͟l͟ ͟o͟r͟d͟e͟r͟
#include <iostream> //needed for std::cout, std::cin
#include <map> //needed for std::map
#include <iomanip> //needed for formating the output (std::setw)
int main()
{
std::string inputString; //user input will be read into this string variable
std::cout << "Enter a string: " << std::endl;
std::getline(std::cin, inputString);
//this map maps the char to their respective count
std::map < char, int > charCount;
//iterate through the inputString
for (char & c: inputString)
{
charCount[c]++;//increment the count for character c
}
std::cout << "Total unique characters are: " << charCount.size() << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << "Character" << std::setw(10) << "Count" << std::endl;
std::cout << "------------------------------------" << std::endl;
for (std::pair < char, int > pairElement: charCount)
{
std::cout << std::setw(4) << pairElement.first << std::setw(13) << pairElement.second << std::endl;
}
return 0;
}
Version 2: Get character count in i͟n͟s͟e͟r͟t͟i͟o͟n͟ ͟o͟r͟d͟e͟r͟
#include <iostream>
#include <map>
#include <iomanip>
int main()
{
std::string inputString;
std::cout << "Enter a string: " << std::endl;
std::getline(std::cin, inputString);
std::map < char, int > charCount;
for (char & c: inputString)
{
charCount[c]++;
}
std::cout << "Total unique characters are: " << charCount.size() << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << "Character" << std::setw(10) << "Count" << std::endl;
std::cout << "------------------------------------" << std::endl;
std::size_t i = 0;
//just go through the inputString instead of map
for(char &c: inputString)
{
std::size_t index = inputString.find(c);
if(index != inputString.npos && (index == i)){
std::cout << std::setw(4) << c << std::setw(13) << charCount.at(c)<<std::endl;
}
++i;
}
return 0;
}

String is out of range

The task is interchange two parts of a word, which contains the dash (i.e we have 1237-456 but should transform it into 456-1237). Here`s my code, it runs but doesnt shows results as a string is out of range and i dk why. It happens in the 1st for, the second iteration ends in the error+ it happens when strlen is 5 and more. The code:
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
int main()
{
int u = 0, y = 0;
string first, second;
int i = 0;
string word;
cout << "Enter the text: " << endl;
getline(cin, word);
int l = size(word);
int f = word.find('-');
cout << "The word has " << l << " characters" << endl << endl;
for (int i = 0; i < f; i++) {
first[i] = word[i];
}
for (int i = f + 1; i < l; i++) {
second[y] = word[i];
y++;
}
cout << endl << second << " - " << first << endl;
}
first and second will not have memory allocated to them. They are initialized as strings of size 0. And for this case I would just use iterators instead of indices (though they could work too, but then you need more manual work to allocate enough room for the target strings and all).
All in all I think your code is mixing 'c' and 'c++' style a bit so here is my example:
#include <algorithm> // for find
#include <iostream>
// #include <cstdlib> // <<== this is "c" not C++
// using namespace std; <<== unlearn this
int main()
{
std::string word{ "Mississippi-delta"};
// std::string has a lenght function use that
std::cout << "The word has " << word.length() << " characters\n";
// "it" will be an iterator to the location of '-' (if any)
auto it = std::find(word.begin(), word.end(), '-');
// it points (beyond) the end of the word if no '-' is found
if (it == word.end())
{
std::cout << "no '-' found in word";
}
else
{
std::string first{ word.begin(),it };
++it; // skip '-'
std::string second{ it,word.end() };
std::cout << second << "-" << first << "\n";
}
return 0;
}
Instead of accessing the elements of first and second, just try using .push_back() to add characters from word.

Why does my vector::erase call throw "vector subscript out of range"?

I'm writing a program that saves words from a .txt file in vector words, calculates how many words are there (num_elements) and prints these words randomly to the screen (no duplicates).
It all works fine up until rw.erase line, which just spits out the error "vector subscript out of range".
Why is my erase call throwing "vector subscript out of range"?
#include <iostream>
#include <string>
#include <fstream>
#include <Windows.h>
#include <direct.h>
#include <filesystem>
#include <time.h>
#include <random>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
void path_to_main_dir() {
string path = "C:/Randomizer/";
for (const auto& entry : experimental::filesystem::directory_iterator(path)) {
cout << entry.path() << endl;
}
}
int main() {
path_to_main_dir();
string dateread;
printf("Which file do you want to open? ");
cout << "---------------------------------------------------------------------------------------------------------" << endl;
path_to_main_dir();
cout << endl;
cout << "---------------------------------------------------------------------------------------------------------" << endl;
cout << "User: ";
getline(cin, dateread);
string path_to_file = "C:/Randomizer/" + dateread + ".txt";
ifstream readfile(path_to_file.c_str());
vector<string> words;
string word;
while (getline(readfile, word))
{
words.push_back(word);
}
readfile.close();
srand(time(NULL));
string randomword;
vector<string> rw = { words };
int num_elements = size(words);
cout << endl;
cout << "Number of words in the file: ";
cout << num_elements;
cout << endl;
for (unsigned int a = 0; a < num_elements; a = a + 1)
{
randomword = rw[rand() % num_elements];
cout << randomword << endl;
rw.erase(remove(rw.begin(), rw.end(), randomword), rw.end());
num_elements -= 1;
system("pause");
}
goto firstline;
return 0;
}
If the error only happens in the case where there are duplicates, it could be because the num_elements is wrong. The remove/erase call will have deleted as many duplicates as there are, but num_elements has only been reduced by one.
Fortunatly, vectors know their own size, so rather than trying to remember its internal information for it, you can just ask!
int main()
{
//...
//Code to read words from file
//...
cout << "Number of words in file: " << words.size() << endl;
while(!words.empty())
{
string randomWord = words[rand() % words.size()];
cout << randomWord << endl;
words.erase(remove(words.begin(), words.end(), randomWord), words.end());
}
return 0;
}
From what I can see, you only use words to create rw, so we could just use words directly instead.

Hangman w/ Functions - Compile Error - No Match for Call To

I've been trying to get this Hangman using functions (from Michael Dawson's book) program to work, but I have this one error that I don't really understand. I realize my code code could have a variety of bad practices, but please go easy on me as I am a newb. I feel like I am almost there but I'm having trouble figuring out this one error. I am using CodeBlocks. The error is:
32|error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string}) (std::__cxx11::basic_string::size_type, char)'|
//Hangman from Michael Dawson's code
//Uses functions to create the program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>
using namespace std;
//FUNCTION DECLARATION
string pickword();
char playerGuess();
void isitinthere();
char guess = 0;
string soFar = "word";
string used = "";
int wrong = 0;
int main()
{
const int MAX_WRONG = 8;
string WORD = pickword();
soFar = WORD;
soFar(WORD.size(), '-');
used = "";
cout << "Welcome to Hangman! Godspeed!" << endl;
while ((wrong < MAX_WRONG) && (soFar != WORD))
{
cout << "\n\nYou have " << (MAX_WRONG - wrong);
cout << " incorrect guesses left.\n";
cout << "\nYou've used the following letters:\n" << used << endl;
cout << "\nSo far, the word is:\n" << soFar << endl;
}
playerGuess();
while (used.find(guess) != string::npos)
{
cout << "\nYou've already guessed " << guess << endl;
cout << "Enter your guess: ";
cin >> guess;
guess = toupper(guess);
}
used += guess;
isitinthere();
if (wrong == MAX_WRONG)
{
cout << "\nYou've been hanged!";
}
else
{
cout << "\nYou guessed it!";
}
cout << "\nThe word was " << WORD << endl;
return 0;
}
//FUNCTION DEFINITION
string pickword()
{
srand(static_cast<unsigned int>(time(0)));
vector<string> words;
words.push_back("INDUBITABLY");
words.push_back("UNDENIABLY");
words.push_back("CRUSTACEAN");
words.push_back("RESPONSIBILITY");
words.push_back("MISDEMEANOR");
words.push_back("FORENSIC");
words.push_back("BALLISTIC");
words.push_back("PARADIGM");
words.push_back("TROUBARDOR");
words.push_back("SUPERCALIFRAGILISTICEXPIALLADOCIOUS")
random_shuffle(words.begin(), words.end());
theword = words[0];
return theword;
}
char playerGuess()
{
cout << "\n\nEnter your guess: ";
cin >> guess;
guess = toupper(guess);
return guess;
}
void isitinthere()
{
if (WORD.find(guess) != string::npos)
{
cout << "That's right! " << guess << " is in the word.\n";
for (int i = 0; i < WORD.length(); ++i)
{
if (WORD[i] == guess)
{
soFar[i] = guess;
}
}
}
else
{
cout << "Sorry, " << guess << "isn't in the word. \n";
++wrong;
}
}
Thanks in advance for your help!
Here is a simple program that should solve your question.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cctype>
// since you must have function here are some
bool removeGuessFromWord(std::string& word, const char guess);
bool isGuessInWord(const std::string& word, const char guess);
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess);
// this is a simple program that should solve your question. It is not optimized for speed or efficency.
int main()
{
std::vector<std::string> wordList = {"dog","cat","rat"}; // vector of words to select from and use as the word in hangman
std::vector<char> guessList; // empty vector of gusses
// Note that I assume a MAX_GUESS_COUNT of 0 means no guesses are allowed
const unsigned int MAX_GUESS_COUNT = 4U; // number of guesses your allowed
std::srand(time(0)); // use current time as seed for random generator
std::string word = wordList.at(std::rand()%wordList.size()); // get a random word in the list
std::string letersLeft = word; // keep track of what letters will still need to remove
std::cout << "Welcome to Hangman! Godspeed!" << std::endl;
char guess = 0;
for(unsigned int numBadGusses=0U; numBadGusses<MAX_GUESS_COUNT && letersLeft.size()>0U; guess = 0)
{
std::cin>>guess;
if(std::isprint(guess) == 0)
{
// may want more error checking
std::cout << "You ented a non-printable charecter" << std::endl;
}
else if(isGuessInWord(word, guess))
{
// this was a good guess because the charecter is still in the word
// so remove all the remaining chars of this type from the word
if( removeGuessFromWord(letersLeft,guess) )
{
std::cout << guess << " was a good guess" << std::endl;
}
else
{
std::cout << guess << " was a good guess, but you already guessed it once" << std::endl;
}
}
else if(hasAlreadyGuessed(guessList, guess))
{
std::cout << "You've already guessed " << guess << std::endl;
}
else
{
// this was a new bad guess
guessList.push_back(guess);
numBadGusses++; // Note that this isn't technicly needed and could use size of vector
std::cout << guess << " was a bad guess" << std::endl;
}
}
if(letersLeft.size() == 0U)
{
std::cout<<"You Win"<<std::endl;
}
else
{
std::cout<<"You Lose"<<std::endl;
}
std::cout << "The word was "<< word << std::endl;
return 0;
}
bool removeGuessFromWord(std::string& word, const char guess)
{
return word.erase(std::remove(word.begin(), word.end(), guess), word.end()) != word.end() ? true : false;
}
bool isGuessInWord(const std::string& word, const char guess)
{
return word.find(guess) != std::string::npos ? true: false;
}
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess)
{
return std::find(gussList.begin(), gussList.end(), guess) != gussList.end() ? true: false;
}

Searching for numbers in a string

User inputs a string in form of
length=10 width=15
The task is to find the length's and width's value in such a string(and assign them to variables). So, how can I find those two numbers? What functions/methods should I use? Can you guys just give me an idea?
Regular expressions are fun and are usually not acceptable as homework solutions for introductory classes.
match[1] and match[2] are the numerical portion of the string that you are interested in. You'll probably want to pass them to stoi() if you need to manipulate them as integers.
Code
#include <iostream>
#include <regex>
int main() {
std::string s("length=10 width=15");
std::regex re("length=([0-9]+) width=([0-9]+)");
std::smatch match;
if (regex_match(s, match, re)) {
std::cout << "length: " << match[1] << "\n";
std::cout << "width: " << match[2] << "\n";
}
}
Output
length: 10
width: 15
use stringstream:
#include <string>
#include <iostream>
#include <sstream>
#include <map>
using namespace std;
int main()
{
stringstream ss;
ss.str("length1=10 width=15 length2=43543545");
map<string, int> resMap;
string key;
int val;
while (ss.peek() != EOF) {
if (isalpha(ss.peek())) {
char tmp[256];
ss.get(tmp,streamsize(256),'=') ;
key = tmp;
} else if (isdigit(ss.peek())) {
ss >> val;
resMap.insert(pair<string, int>(key,val));
} else {
ss.get();
}
}
cout << "result:\n";
for (map<string, int>::iterator it = resMap.begin(); it != resMap.end(); ++it) {
cout << "resMap[" << it->first<< "]=" << it->second << endl;
}
getchar();
return 0;
}