从Arduino上的String中提取int

时间:2016-09-25 04:27:47

标签: c++ c int substring arduino-uno

我有一个随机字符缓冲区从XBee模块流入我的Arduino。我想提取它看到的第一个整数(如果这会产生差异,将是< = 3位数int),然后继续使用该数字并停止查看其余的传入字符。

作为参考,我试图将此作为与node.js服务器的双向握手的一部分,当其他Arduinos也试图握手或已连接时,该服务器不会搞砸并发送数据。

我认为我有一种方法可以提取一个int,但它看起来真的很难看,所以我认为必须有一个更短/更清洁的方法来解决这个问题。这是我很长的代码,可以做一些可能非常简单的事情:

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);

非常感谢任何建议/意见。

4 个答案:

答案 0 :(得分:3)

不要与0到9之间的每个数字进行比较,而是使用标准C函数isdigit()

答案 1 :(得分:2)

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"

假设msg的第一个字符是数字:

  1. intStart设为0
  2. 获取msg的第一个字符
  3. 虽然intStart尚未2
  4. 如果intStart为0(它是,我们没有调整它)并且msg的第一个字符是数字(我们假设它是),然后将第一个字符追加到{ {1}}并制作intString
  5. intStart = 1如果(它是,我们在prev步骤设置它)并且msg的第一个字符是数字(它仍然是第一个,intStart == 1没有更改),然后将第一个字符追加到i(很好,现在我有两次)并设置intString(嘿,intStart=1没有改变)。否则......我们可以忽略其他情况,我们处于intStart
  6. 的良好条件
  7. 所以回到第3步,thenintStart==1仍为0,而msg的第一个字符仍为数字。
  8. 我应该继续还是能够做到?

    本质上,msg的第一个字符是一个数字,你永远不会从i离开,直到由于while (intStart != 2)通过重复相同的fisrt char而增加了堆空间到处都是。

    这就是你想要的吗?

    在询问之前向你的橡皮鸭解释这个是不是很难?
    (是的,我明白,Arduino没有调试器,但你仍然可以使用Serial。打印)

答案 2 :(得分:1)

[评论更新]

  

很抱歉,如果我不清楚,但它不一定以整数开头,整数可能在char缓冲区的中间。

     

任何长度的char缓冲区中的第一个数字序列(实际上不必限制为最多3位数,只要它更容易)

所以,在说明收集之前,我们只需要将自己定位在字符串缓冲区的第一个数字

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

如果您不需要intString,只需intValue,请不要使用intString - 最多bool hasDigits来初始化false 1}}并设置为true代替intString += msg[startScan];(作为“没有遇到数字&#39;情况”的信号)。

如果您不需要intValue,只需从使用它的代码中删除即可。

因此,如果我的提示不正确,则会出现以下问题:

  

我有一条String消息,该消息以最多 3个十进制数字开头,并可能与我不需要的其他信息结束。我希望这个“最多3位数字”#39;前缀转换为整数,供我进一步使用

如果这是你的问题,那就试试这个:

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

如果Arduino没有isdigit功能,您可以实现自己的功能

int isdigit(char c) {
  // we are using ASCII encoding for characters, aren't we?
  return (c>='0' && c <='9');
}

答案 3 :(得分:0)

一种方法是使用String对象。这有一个toInt方法。

BTW有一个Arduino特定的堆栈交换。 arduino.stackexchange.com