How can a char value be converted to a specific int value - c++

I have an assignment where I have to make a program that allows a person to input a seven letter word and converts it to a telephone number (1-800-PAINTER to 1-800-724-6837 for example). I'm trying to make each letter convert to a specific number to be outputted to the user, with each letter corresponding to its number on a telephone keypad (so a, A, b, B or c, C equals 1, i.e, more info: https://en.wikipedia.org/wiki/Telephone_keypad).
Currently I have it set up so that each letter of the input word represents a char variable of one, two, three, four, five, six, or seven respectively. Then, using switch and if statements, the idea was to convert a char to an int variable of xtwo = 2, xthree = 3, etc. This isn't working however. Is there a better way to do this?
Example of code (up to first switch, though mostly it's a repeating pattern like so):
int main()
{
char one, two, three, four, five, six, seven;
cout << "Enter seven letter word (1-800-***-****): " << "\n";
cin >> one >> two >> three >> four >> five >> six >> seven;
int xtwo = 2; int xthree = 3; int xfour = 4; int xfive = 5; int xsix = 6; int xseven = 7; int xeight = 8;
int xnine = 9;
switch (one)
{
case 1:
if (one == 'a' || one == 'b' || one == 'c' || one == 'A' || one == 'B' || one == 'C')
{
one = xtwo;
}
break;
case 2:
if (one == 'd' || one == 'e' || one == 'f' || one == 'D' || one == 'E' || one == 'F')
{
one = xthree;
}
break;
case 3:
if (one == 'g' || one == 'h' || one == 'l' || one == 'G' || one == 'H' || one == 'L')
{
one = xfour;
}
break;
case 4:
if (one == 'j' || one == 'k' || one == 'l' || one == 'J' || one == 'K' || one == 'L')
{
one = xfive;
}
break;
case 5:
if (one == 'm' || one == 'n' || one == 'o' || one == 'M' || one == 'N' || one == 'O')
{
one = xsix;
}
break;
case 6:
if (one == 'p' || one == 'q' || one == 'r' || one == 's' || one == 'P' || one == 'Q' || one == 'R' || one == 'S')
{
one = xseven;
}
break;
case 7:
if (one == 't' || one == 'u' || one == 'v' || one == 'T' || one == 'U' || one == 'V')
{
one = xeight;
}
break;
case 8:
if (one == 'w' || one == 'x' || one == 'y' || one == 'z' || one == 'W' || one == 'X' || one == 'Y' || one == 'Z')
{
one = xnine;
}
break;
}
So, in essence, how can a char variable of a letter be converted to a specific int variable?

You could use a std::map.
For example, you could have
std::map<char,int> char_to_dig {
{'a',1}, {'b',1}, {'c',1},
{'d',2}, {'e',2}, {'f',2}
};
Then
char_to_dig['a']
will give you 1.
Alternatively, you could write a function that does the mapping. Something along the lines of this:
int char_to_dig(char c) {
static const char _c[] = "abcdefghi";
static const int _i[] = { 1,1,1,2,2,2,3,3,3 };
for (unsigned i=0; i<9; ++i) {
if (_c[i]==c) return _i[i];
}
return -1; // some value to signal error
}
Or, instead of using arrays, you could perform arithmetic on the chars (since they are just small integers).
int char_to_dig(char c) {
c = std::toupper(c);
if (c < 'A' || c > 'Z') return -1;
if (c == 'Z') return 9;
if (c > 'R') --c;
return ((c-'A')/3)+2;
}
This will give you numbers like on this pad:
Apparently, there's been a similar code golf question.

It has been years since I wrote any c/c++ code and I don't even have a compiler installed to test with .. but this should get you started on the right track
Check functions and syntax...all out of my head. Needs checking.
//
int numArray[7];
char inputStr[10];
cout << " give me 7 characters";
cin >> input;
/*
use a for loop to read the string letter by letter (a string in c is an
array of characters)
convert the characters to uppercase
fall through case statements for each group of letters
assing value to output array to do wiht as you like.
*/
for(i=0; i < 7; i++){
inputStr[i] = toupper(inputStr[i]);
switch(input[i]){
case 'A':
case 'B':
case 'C':
numArray[i] = 2;
break;
case 'D':
case 'E':
case 'F':
numArray[i] = 3;
break;
and so on and so foth....
}
}

Related

How do I remove the first full number of a string as an integer C++

How do I remove the first full number of a string as an integer in C++
for instance a string "thdfwrhwh456dfhdfh764"
Would need to only pull out the first number 456 as an integer.
Thanks
Start by finding the first digit:
std::size_t pos = str.find_first_of(“0123456789”);
then check whether a digit was found:
if (pos != std::string::npos)
and then extract the tail of the string:
std::string tail = str.substr(pos);
and then extract the value:
int value = std::stoi(tail);
Here is a good example of how you might go about reading only the first number of a string that appears:
const char string_c[] = "this is a number 67theaksjdhflkajsh 78";
std::string string_n;
bool exitable = false;
for (int i = 0; i < sizeof(string_c); i++)
{
char value = string_c[i];
if (value == '0' ||
value == '1' ||
value == '2' ||
value == '3' ||
value == '4' ||
value == '5' ||
value == '6' ||
value == '7' ||
value == '8' ||
value == '9')
{
string_n += string_c[i];
exitable = true;
} else if (exitable == true)
{
printf("break\n");
break;
}
}
printf("this is the number: %s ", string_n.c_str());
If you need the number as int then you can use the std::stoi() function.

Recursive function that counts vowels

I have an assignment that asks me to "Write a recursive function vowels(s,low,high) that returns the number of vowels in an input string s[]." We are also limited by "Do not use the C++ string type. Read the characters into an array one at a time using cin.get()." I think I solved the task at hand, but it doesnt compile so I am unsure. If anyone could assist me and show how to fix my error and any errors I've made towards my solution that would be great.
Here is my error message.
***main.cpp:24:37: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
vowelCount = vowels(s, low, high);**
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
int vowels(char, int, int);
int main()
{
char s[500];
int high,
vowelCount,
low = 0;
cout << "Enter a string of characters: ";
cin.get(s, 500);
high = strlen(s);
vowelCount = vowels(s, low, high);
cout << "The string contains " << vowelCount << " vowels." << endl;
return 0;
}
int vowels(char s[], int low, int high)
{
if (s[low] == 'a' || 'A' || 'e' || 'E' || 'i' || 'I' || 'o' || 'O' || 'u' || 'U') {
return 1 + vowels(s, low + 1, high - 1);
} else {
return vowels(s, low + 1, high - 1);
}
}
We are talking about a so called XY-Problem here.
The teacher wants to cover recursive functions. The vowel counting is just some noise. Unfortunately the given example is a bad one, because it could be implemented by far better with an iterative approach.
The recursion is just adding unnecessary time and space complexity. So, the performance is worse compared to a simple loop in all cases.
If the teacher wants that you learn about recursion, you may want to first look at this description or that more practical example.
After having read this, you will understand that a loop can be simply converted into a recursive function.
I am not sure, why there is a "low" and a "high" parameter. Maybe because of the usage of C-strings stored in a char array (what is nonsense in C++). I doubt that 2 self calls should be established and the function should walk from the begin and the end of the string to the middle. That would even further reduce the performance. So, let us assume the standard case.
Next to your problem with the comparison. What you have written is wrong. The correct comparison in C++ would be:
if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') ||
(s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') ||
(s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') ||
(s[low] == 'U'))
Of course, nobody would write such a long statement, because you can simply calculate, without any comparison, if an ASCII character is a vowel. You could simply write:
if (std::isalpha(s[low]) && ((0x208222 >> (s[low] & 0x1f)) & 1))
and thats it. If you are interested, I can explain the theory later, but not needed for this example.
Then, next, your recursive function is dangerously wrong, because it does not have an end condition. it will run forever or until the stack overflows.
So, you need to rework that, It could be done like this:
#include <iostream>
#include <cstring>
using namespace std;
int vowels(char[], int, int);
int main()
{
char s[500];
int high,
vowelCount,
low = 0;
cout << "Enter a string of characters: ";
cin.get(s, 500);
high = strlen(s);
vowelCount = vowels(s, low, high);
cout << "The string contains " << vowelCount << " vowels." << endl;
return 0;
}
int vowels(char s[], int low, int high)
{
int sum = 0;
if (low != high) {
if ((s[low] == 'a') || (s[low] == 'A') || (s[low] == 'e') ||
(s[low] == 'E') || (s[low] == 'i') || (s[low] == 'I') ||
(s[low] == 'o') || (s[low] == 'O') || (s[low] == 'u') ||
(s[low] == 'U'))
{
++sum;
}
sum += vowels(s,low+1,high);
}
return sum;
}
If we go a little bit more into the direction of C++ and use meaningful variable names and comments, then we could come up with that:
#include <iostream>
#include <cstring>
// A recursive function to count the vowels in a rang of a text
int countVowelsRecursive(char textToEvaluate[], unsigned int startPositionForEvaluation, unsigned int endPositionOfText)
{
// Here we will store the number of vowels. We will use tail recursion
// So, the overall calculation will be done at the end
unsigned int numberOfVowelsInThisRecursion = 0u;
// Now we are evaluating this character from the text
const char currentChar = textToEvaluate[startPositionForEvaluation];
// Check, for the end of recursion condition
if (startPositionForEvaluation != endPositionOfText) {
// Check, if it is a vowel
if ((currentChar == 'a') || (currentChar == 'A') || (currentChar == 'e') ||
(currentChar == 'E') || (currentChar == 'i') || (currentChar == 'I') ||
(currentChar == 'o') || (currentChar == 'O') || (currentChar == 'u') ||
(currentChar == 'U'))
{
// Vowel found. Increase counter by one
++numberOfVowelsInThisRecursion;
}
// Tail recursion. Self call, starting at next position of the string
numberOfVowelsInThisRecursion +=
countVowelsRecursive(textToEvaluate,startPositionForEvaluation + 1, endPositionOfText);
}
// This will be the final result
return numberOfVowelsInThisRecursion;
}
// We will allow a maximal input text length like this
constexpr unsigned int MaxTextLength = 500u;
// Driver code / test function
int main()
{
// Here we will store the text from the user
char text[MaxTextLength]{};
// Give instructions and get the text
std::cout << "Enter a string of characters: ";
std::cin.get(text, MaxTextLength);
// Set text parameters for the evaluation
unsigned int startOfText = 0u;
unsigned int endOfText = static_cast<unsigned int>(strlen(text));
// Calculate the vowels
unsigned int vowelCount = countVowelsRecursive(text, startOfText, endOfText);
// Show result to user
std::cout << "The string contains " << vowelCount << " vowels." << std::endl;
return 0;
}
And if we would be allowed to use C++ then we would write:
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
// Give instructions and get the text
std::cout << "\nEnter a text:\n";
if (std::string text{}; std::getline(std::cin, text))
// Show result to user
std::cout << "\n\nThe string contains "
<< std::count_if(text.begin(), text.end(), [](const char c){ return std::isalpha(c) && ((0x208222 >> (c & 0x1f)) & 1);})
<< " vowels.\n";
return 0;
}
Have fun . . .

Extracting int from String on Arduino

I have a buffer of random characters streaming into my Arduino from a XBee module. I want to extract the first integer that it sees (will be <= 3-digit int if that makes a difference), then move on with that number and stop looking at the rest of the incoming characters.
For reference, I'm trying to use this as part of a 2-way handshake with a node.js server that doesn't get messed up when other Arduinos are also attempting to handshake or are already connected and sending data.
I think I have a way that might work to extract an int, but it seems really ugly, so I'm thinking there must be a much shorter/cleaner way to go about this. Here's my very long code to do something that's probably pretty simple:
String intString = "";
int intStart = 0;
for (int i = 0; i < msg.length(); i++) {
while (intStart != 2) {
if (intStart == 0) {
if ((msg[i] == '0') || (msg[i] == '1') || (msg[i] == '2') ||
(msg[i] == '3') || (msg[i] == '4') || (msg[i] == '5') ||
(msg[i] == '6') || (msg[i] == '7') || (msg[i] == '8') ||
(msg[i] == '9')) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is still int
if (intStart == 1) {
if ((msg[i] == '0') || (msg[i] == '1') || (msg[i] == '2') ||
(msg[i] == '3') || (msg[i] == '4') || (msg[i] == '5') ||
(msg[i] == '6') || (msg[i] == '7') || (msg[i] == '8') ||
(msg[i] == '9')) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is not int
else if ((msg[i] != '0') && (msg[i] != '1') && (msg[i] != '2') &&
(msg[i] != '3') && (msg[i] != '4') && (msg[i] == '5') &&
(msg[i] != '6') && (msg[i] != '7') && (msg[i] == '8') &&
(msg[i] != '9')) {
intStart = 2;
}
}
}
int number = intString.toInt();
Serial.println(number);
Any suggestions/advice is greatly appreciated.
Rather than compare against every number from 0 to 9, use the standard C function isdigit().
String intString = "";
int intStart = 0;
for (int i = 0; i < msg.length(); i++) {
while (intStart != 2) {
if (intStart == 0) {
if (isdigit(msg[i])){
intString += msg[i];
intStart = 1;
}
}
// previous int, next is still int
if (intStart == 1) {
if (isdigit(msg[i])) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is not int
else if ( isdigit(msg[i]) ) {
intStart = 2;
}
}
}
"Rubber duck debugging":
Let's assume the first char of the msg is a digit:
set intStart to 0
take the first char of the msg
while intStart is not yet 2
if intStart is 0 (it is, we haven't adjusted it) and the first char of the msg is digit (we assumed it is), then append the first char to intString and make intStart = 1
if intStart == 1 (it is, we set it at the prev step) and the first char of the msg is digit (it is still the first, i didn't change), then append the first char to intString (great, now I have it twice) and set intStart=1 (hey, intStart didn't change). Else... well, we can ignore else, we are in the good conditions for then
so back to the step 3, with the intStart==1 and i still 0 and the first char of the msg still a digit.
Should I continue or are you able to do it?
In essence, with the first char of the msg a digit, you'll never get out from while (intStart != 2) until you run out of heap-space due to intString growing by repeating the same fisrt char all over.
Is that what you want?
Is it so hard to explain this to your rubber duck before asking SO?(yes, I understand, Arduino doesn't have a debugger, but you still can use Serial.print)
[Update on the comments]
Sorry if I was unclear, but it doesn't necessarily start with an integer, the integer could be in the middle of the char buffer.
The first sequence of digits in the char buffer of any length (really doesn't have to be restricted to max 3-digit, only if it makes it easier)
So, before stating to collect, we just need to position ourselves on the first digit of the string buffer
int startScan=0;
// no body for the cycle, everything works just from
// the exit condition and increment
for(
;
startScan < msg.length() && ! isdigit(msg[i]); // as long as it's not a digit
startScan++
);
// from this position, start collecting for as long as we have digits
int intValue=0;
String intString;
for(; startScan < msg.length() && isdigit(msg[startScan]); startScan++) {
intString += msg[startScan]; // take it inside the string
// careful with this one, it may overflow if too many digits
intValue = intValue*10 + (msg[startScan]-'0');
}
// if we reached here with an empty intString, we didn't find any digits
If you don't need the intString, just the intValue, don;t use the intString - at most a bool hasDigits to init to false and set to true in place of intString += msg[startScan]; (to act as a signal for the 'no digits encountered' case).
If you don't need the intValue, just wipe out from the code anithing that uses it.
So, if my understating is correct, you have the following problem:
I have a String message which starts by at most 3 decimal digits and ends possibly with other info I don't need. I want that 'at most 3 digits' prefix transformed in an integer for me to use further
If this is you problem, then try this:
int intValue=0;
String intString;
int maxLookInto=(msg.length() > 3 ? 3 : msg.length()); // at most 3 digits
for(int i=0; i<maxLookInto && isdigit(msg[i]); i++) {
// if we got here, we know msg[i] is still a digit, otherwise
// we get out of cycle ealier
intString += msg[i]; // take it inside the string
intValue = intValue*10 + (msg[i]-'0'); // transforming in base 10 in an int
}
// Do what you like with either intString (textual representation of the
// at-most-3-digits or with the same value converted already to a number
// in intValue
If Arduino doesn't have the isdigit function available, you can implement your own like
int isdigit(char c) {
// we are using ASCII encoding for characters, aren't we?
return (c>='0' && c <='9');
}
One way is to use the String object. This has a toInt method.
BTW there is an Arduino specific stack exchange. arduino.stackexchange.com

Logic Error in TicTacToe game

here's a simple logic error I can't quite wrap my head around:
Why does the following statement always equate to true?
if ( (grid[i][0] && grid[i][1] && grid[i][2]) == ('X' || 'x') ) return true;
It works flawlessly for
if ( (grid[i][0] && grid[i][1] && grid[i][2]) == ('X') return true;
Do it like this:
create a function to check a character of being x:
bool isX(char c)
{
return c == 'X' || c == 'x';
}
and the you can write:
if ( isX(grid[i][0]) && isX(grid[i][1]) && isX(grid[i][2]))
return true;
That's because the expressions
'X' || 'x'
and
grid[i][0] && grid[i][1] && grid[i][2]
use the || and && operators between non-zero integer-typed values (because char is an integer type) and so they both evaluate to true.
To translate into C++ (or almost any other somewhat similar language, for that matter) that you want characters x, y and z to be equal to either of the characters c and C, you must compute
(x == c || x == C) && (y == c || y == C) && (z == c || z == C)
so apply that to your problem.
More importantly though, learn about boolean operators and programming in general before you try to tackle C++.
In the first case, it returns true because none of the grid elements has the value of zero. The && operator produces 0 or 1, depending on the values that you pass.
In the second case, it does not work as expected either: you wouldn't get an 'X' by &&-ing values together.
The proper way of checking if three items are equal to 'X' or not would be as follows:
if (toupper(grid[i][0]) == 'X'
&& toupper(grid[i][1]) == 'X'
&& toupper(grid[i][2]) == 'X') {
return true;
}
To generalize the concept of "win" in TiCTacToe, write a function that returns true when a sequence of three items with a specific step in each direction holds a sequence of a given character, like this:
bool isWin(int r, int c, int dr, int dc, char ch) {
return toupper(grid[r+0*dr][c+0*dc] == ch
&& toupper(grid[r+1*dr][c+1*dc] == ch
&& toupper(grid[r+2*dr][c+2*dc] == ch;
}
bool isWin(char ch) {
return isWin(0,0,0,1,ch)
|| isWin(0,0,1,0,ch)
|| isWin(1,0,0,1,ch)
|| isWin(0,1,1,0,ch)
|| isWin(2,0,0,1,ch)
|| isWin(0,2,1,0,ch)
|| isWin(0,0,1,1,ch)
|| isWin(2,0,-1,1,ch);
}

c++ count amount of numbers in char array?

I have a char array that has number 0-8 in it in char form
Board[0] = '0';
Board[1] = '1';
Board[2] = '2';
Board[3] = '3';
Board[4] = '4';
Board[5] = '5';
Board[6] = '6';
Board[7] = '7';
Board[8] = '8';
and some of them are changed to either an 'x' or an 'o' based on user input however I need to figure out a way so that I can tell the total number of them that aren't an 'x' or an 'o'.
What I mean is if say 4 of the 9 are either an 'x' or an 'o' I need to be able to get the fact that there are 5 left. I was attempting to use for each(char c in Board) and I got far enough to where I got it to list the chars that aren't an 'x' or an 'o' but I can't figure out how to get it to send how many are left to an int value. This is as far as I got.
for each(char c in Board)
{
if (c != 'x' && c != 'o')
{
}
}
You could try
auto n = std::count_if(Board, Board+9, std::isdigit);
You should define a counter that counts the number of these characters (by incrementing it):
int n = 0;
for (char c : Board)
{
if (c != 'x' && c != 'o')
{
n++; // increment n by 1
}
}
std::cout << n << '\n'; // use the result
You can use a combination of std::isdigit and std::count_if
#include <cctype> // for std::isdigit
#include <algorithm> // for std::count_if
int num = std::count_if(Board, Board+9, std::isdigit);
Assuming you don't just want any digit, and only those between 0 and 8 you could do this:
int count = 0;
for each(char c in Board)
{
if (c >= '0' && c <= '8')
{
count++;
}
}
cout << count << " are digits between 0 and 8 (inclusive)" << endl;