I'm fairly new to programming and I'm trying to get a function working that converts a string to an int. My idea with this function was to collect every number in the string and store it in another string, then convert it to an int.
The function returns the value 0.
What this function is supposed to do is return the converted number. Which should not be 0.
int getNumberFromString(int convertedNumber, string textToConvert)
{
for (int i = 0; i < textToConvert.size(); i++)
{
string collectNumbers;
int j = 0;
if (textToConvert[i] == '1' || textToConvert[i] == '2' || textToConvert[i] == '3' ||
textToConvert[i] == '4' || textToConvert[i] == '5' || textToConvert[i] == '6' ||
textToConvert[i] == '7' || textToConvert[i] == '8' || textToConvert[i] == '9' || textToConvert[i] == '0')
{
collectNumbers[j] = textToConvert[i];
j++;
}
if (collectNumbers.size() == 0)
{
return false;
}
else if (collectNumbers.size() > 0)
{
stringstream convert(collectNumbers);
if (!(convert >> convertedNumber))
{
convertedNumber = 0;
}
return convertedNumber;
}
}
}
Maybe you should just use library function ?
int stoi (const string& str, size_t* idx = 0, int base = 10);
You want somehting more like:
int getNumberFromString(int convertedNumber, string textToConvert) {
int retval = 0;
for (auto c: textToConvert) {
retval *= 10;
retval += c - '0';
}
return retval;
}
if you need to code it, or simply use stoi()
Your MAIN problem is that you are trying to convert the number before you have collected all the digits. You should loop over all the digits (use isdigit or if (x >= '0' && x <= '9') to avoid long list of individual digits - or, if you really like to list all digits, use switch to make it more readable).
Once you have collected all the digits, then convert AFTER the loop.
The statement return false, will be the same as return 0; since false will get converted to an integer with the value zero. So you won't be able to tell the difference between reading the value zero from a string and returning false (this is not PHP or JavaScript where type information is included in return values).
Related
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.
The function below convert a string to integer, making use of std::accumulate.
It first checks the presence of a sign and skips it.
The parameter c of lambda is fine as it just goes through all the remaining characters of input string s. But what about the first lambda parameter sum? How does it know that it should initialise sum to zero? And does the order of these lambda parameters matter?
int string2int(const string &s)
{
return (s[0] == '-' ? -1 : 1) *
accumulate(begin(s) + (s[0] == '-' || s[0] == '+'), end(s), 0,
[](int sum, char c) {
return sum * 10 + c - '0';
});
}
Btw, equivalent code without using std::accumulate would look something like this:
int string2int(const string &s)
{
int sign = (s[0] == '-' ? -1 : 0);
sign = (s[0] == '+' ? 1 : sign);
int index = 0;
if(sign != 0)
{
++index;
}
int result = 0;
for (auto i = index; i < s.size(); ++i)
{
result = result * 10 + (s[i] - '0');
}
sign = (sign < 0 ? -1 : 1);
return result * sign;
}
The parameter between end(s) and the lambda is the initial value.
Could be 1, for example, if you wanted product.
The first lambda parameter is the accumulated data, the second is the current element of the sequence.
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
I'm working on a Caesar Cipher program for an assignment and I have the general understanding planned out, but my function for determining the decipher key is unnecessarily long and messy.
while(inFile().peek != EOF){
inFile.get(character);
if (character = 'a'|| 'A')
{ aCount++; }
else if (character = 'b' || 'B')
{ bCount++; }
so on and so on.
What way, if it's possible, can I turn this into an array?
You can use the following code:
int count [26] = {0};
while(inFile().peek != EOF){
inFile.get(character);
if (int (character) >=65 || int (character) <=90)
{ count [(int (character)) - 65] ++; }
else if (int (character) >=97 || int (character) <=122)
{ count [(int (character)) - 97] ++; }
}
P.S. This is checking for the ASCII value of each character and then increment its respective element in the array of all characters, having 0 index for A/a and 1 for B/b and so on.
Hope this helps...
P.S. - There was an error in your code, = is an assignment operator and == is a conditional operator and you do not assign value in if statement, you check for condition... So always use == to check for equality...
You can use an array in the following manner
int letterCount['z'] = {0}; //z is the highest letter in the uppercase/lowercase alphabet
while(inFile().peek != EOF){
inFile.get(character);
if (character > 'A' && character < 'z')
letterCount[character]++;
}
You can also use a hashmap like this
#include <unordered_map>
std::unordered_map<char,int> charMap;
while(inFile().peek != EOF){
inFile.get(character);
if (charMap.find(character) == charMap.end())
charMap[character] = 1;
else
charMap[character] = charMap[character] + 1;
}
In case you do not know, a hashmap functions as an array, where the index can be any class you like, as long as it implements a hash function.
I have a char * which contains year and month lets say YYYYMM. How can I compare MM within the range of 01 to 12 ? Do I have to do atoi for the substring and do it or anything else exists?
If the first character of the month portion of the string is '0' the second must be between '1' and '9' inclusive to be valid. If the first character is '1' the second must be between '0' and '2' inclusive to be valid. Any other initial character is invalid.
In code
bool valid_month (const char * yyyymm) {
return ((yyymm[4] == '0') && (yyymm[5] >= '1') && (yyymm[5] <= '9')) ||
((yyymm[4] == '1') && (yyymm[5] >= '0') && (yyymm[5] <= '2'));
}
You can do atoi() of the substring or you can simply compare the ASCII values. For example:
if (buf[4] == '0')
{
// check buf[5] for values between '1' and '9'
}
else if (buf[4] == '1')
{
// check buf[5] for values between '0' and '2'
}
else
{
// error
}
Either way is acceptable. I guess it really depends on how you will eventually store the information (as int or string).
Assuming your char* variable is called "pstr" and is null terminated after the MM you can do:
int iMon = atoi(pstr + 4);
if ( (iMon >= 1) && (iMon <= 12) )
{
// Month is valid
}