在 Arduino 上从字符串中提取整数
Extracting int from String on Arduino
我有一个随机字符缓冲区从 XBee 模块流入我的 Arduino。我想提取它看到的第一个整数(如果有所不同,将是 <= 3 位整数),然后继续使用该数字并停止查看其余的传入字符。
作为参考,我正在尝试将其用作与 node.js 服务器的双向握手的一部分,当其他 Arduino 也试图握手或已经连接时,服务器不会搞砸和发送数据。
我想我有一种方法可以提取一个 int,但它看起来真的很难看,所以我认为必须有很多 shorter/cleaner 方法来解决这个问题。这是我很长的代码,用来做一些可能非常简单的事情:
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);
非常感谢suggestions/advice。
与其比较从 0 到 9 的每个数字,不如使用标准 C 函数 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;
}
}
}
假设消息的第一个字符是数字:
- 将
intStart
设置为0
- 获取消息的第一个字符
- 而
intStart
还没有 2
</code> 如果 <code>intStart
为 0(是,我们没有调整)并且消息的第一个字符是数字(我们假设是),然后将第一个字符附加到 intString
并使 intStart = 1
</code> if <code>intStart == 1
(是的,我们在上一步设置了它)并且消息的第一个字符是数字(它仍然是第一个,i
没有改变),然后将第一个字符附加到 intString
(很好,现在我有两次)并设置 intStart=1
(嘿,intStart
没有改变) . else...好吧,我们可以忽略else,我们处于then
的良好条件
- 所以回到第 3 步,
intStart==1
和 i
仍然是 0,消息的第一个字符仍然是数字。
我应该继续还是你能做到?
本质上,由于 msg 的第一个字符是数字,你永远不会从 while (intStart != 2)
中退出,直到你 运行 离开堆-space 由于 intString
通过重复相同的第一个字符来增长。
这是你想要的吗?
在问之前向你的橡皮鸭解释这个有那么难吗?
(是的,我明白,Arduino 没有调试器,但是你仍然可以使用 Serial.print)
[评论更新]
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)
所以,在声明收集之前,我们只需要将自己定位到字符串缓冲区的第一位
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
并设置为 true
代替 intString += msg[startScan];
(作为 'no digits encountered' 情况的信号)。
如果您不需要 intValue
,只需从使用它的代码中清除即可。
所以,如果我的理解是正确的,那么你会遇到以下问题:
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
如果这是你的问题,那么试试这个:
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
功能,您可以实现自己的 like
int isdigit(char c) {
// we are using ASCII encoding for characters, aren't we?
return (c>='0' && c <='9');
}
一种方法是使用 String object. This has a toInt 方法。
顺便说一句,有一个 Arduino 特定的堆栈交换。 arduino.stackexchange.com
我有一个随机字符缓冲区从 XBee 模块流入我的 Arduino。我想提取它看到的第一个整数(如果有所不同,将是 <= 3 位整数),然后继续使用该数字并停止查看其余的传入字符。
作为参考,我正在尝试将其用作与 node.js 服务器的双向握手的一部分,当其他 Arduino 也试图握手或已经连接时,服务器不会搞砸和发送数据。
我想我有一种方法可以提取一个 int,但它看起来真的很难看,所以我认为必须有很多 shorter/cleaner 方法来解决这个问题。这是我很长的代码,用来做一些可能非常简单的事情:
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);
非常感谢suggestions/advice。
与其比较从 0 到 9 的每个数字,不如使用标准 C 函数 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;
}
}
}
假设消息的第一个字符是数字:
- 将
intStart
设置为0
- 获取消息的第一个字符
- 而
intStart
还没有2
</code> 如果 <code>intStart
为 0(是,我们没有调整)并且消息的第一个字符是数字(我们假设是),然后将第一个字符附加到intString
并使intStart = 1
</code> if <code>intStart == 1
(是的,我们在上一步设置了它)并且消息的第一个字符是数字(它仍然是第一个,i
没有改变),然后将第一个字符附加到intString
(很好,现在我有两次)并设置intStart=1
(嘿,intStart
没有改变) . else...好吧,我们可以忽略else,我们处于then
的良好条件
- 所以回到第 3 步,
intStart==1
和i
仍然是 0,消息的第一个字符仍然是数字。
我应该继续还是你能做到?
本质上,由于 msg 的第一个字符是数字,你永远不会从 while (intStart != 2)
中退出,直到你 运行 离开堆-space 由于 intString
通过重复相同的第一个字符来增长。
这是你想要的吗?
在问之前向你的橡皮鸭解释这个有那么难吗?
(是的,我明白,Arduino 没有调试器,但是你仍然可以使用 Serial.print)
[评论更新]
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)
所以,在声明收集之前,我们只需要将自己定位到字符串缓冲区的第一位
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
并设置为 true
代替 intString += msg[startScan];
(作为 'no digits encountered' 情况的信号)。
如果您不需要 intValue
,只需从使用它的代码中清除即可。
所以,如果我的理解是正确的,那么你会遇到以下问题:
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
如果这是你的问题,那么试试这个:
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
功能,您可以实现自己的 like
int isdigit(char c) {
// we are using ASCII encoding for characters, aren't we?
return (c>='0' && c <='9');
}
一种方法是使用 String object. This has a toInt 方法。
顺便说一句,有一个 Arduino 特定的堆栈交换。 arduino.stackexchange.com