Jake Jake - 2 months ago 22
C Question

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.

Answer
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:

  1. set intStart to 0
  2. take the first char of the msg
  3. while intStart is not yet 2
  4. 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
  5. 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
  6. 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)