我的外部设备每隔5秒发送一次数据,如下所示:
+DATA: 43 BYTES FROM 0000:0000 (043)
Nodo_8:(T=21.45,HR=45.65,DW=9.34,Vcc=3.46V)
我需要一些值来保存它们在mysql数据库中。因此,使用strtok我想获得值043,21.45,45.65,9.34,3.46。
我编写了以下代码,它从设备中读取缓冲区:
int learn_port(int fd)
{
int n;
char buff[83];
for (;;)
{
n=read(fd,buff,83);
printf("%s", buff);
char dev_a[25] = "", temp_a[25] = "", hr_a[25] = "", dw_a[25] = "", vcc_a[25] = "";
char* ptr;
ptr = strtok(buff, "+DATA:BYTESFROM()\nNodo_ ,=T:HR:DW:Vcc()");
int i = 0;
while (ptr != NULL)
{
ptr = strtok(NULL, "+DATA:BYTESFROM()\nNodo_ ,=T:HR:Dw:Vcc()");
if (i == 2)
strcat(dev_a, ptr); // copies device
if (i == 5)
strcat(temp_a, ptr); // copies T
if (i == 6)
strcat(hr_a, ptr); // copies HR
if (i == 7)
strcat(dw_a, ptr); // copies DW
if (i == 10)
strcat(vcc_a, ptr);
i++;
}
sleep(1);
printf("%s, %s, %s, %s, %s\n", dev_a, temp_a,hr_a,dw_a,vcc_a);
}
但我有一些奇怪的结果,我不知道哪里有问题。终端第一次回来了:
+DATA: 43 BYTES FROM 0000:0000 (043)
Nodo_8:(T=21.45,HR=45.65,DW=9.34,Vcc=3.46V)
??,??043, 21.45, 45.65, 9.34, 3.46
5秒后
+DATA: 43 BYTES FROM 0000:0000 (043)
Nodo_8:(T=21.23,HR=42.65,DW=9.45,Vcc=3.46V)
?3.46043, 21.23, 42.65, 9.45, 3.46
5秒后
+DATA: 43 BYTES FROM 0000:0000 (051)
Nodo_8:(T=21.67,HR=42.45,DW=9.23,Vcc=3.46V)
?3.46051, 21.67, 42.45, 9.23, 3.46
等。 有没有人知道问题出在哪里?我有?3.46之前的051? strtok有什么问题吗? 我的结果想要是043,21.67,42.45,9.23,3.46
答案 0 :(得分:2)
我相信你错误地理解strtok()
的第二个论点;它不是一个完整的分隔符字符串,它是一组“字符”。换句话说,字符串中的每个字符都被视为有效的分隔符。
有关详细信息,请参阅the manual page,请注意:
delim参数指定一组字节,用于分隔已解析字符串中的标记。
一般来说,这看起来像是应该使用普通sscanf()
解决的问题,不需要使用strtok()
,这更低级且更棘手。
答案 1 :(得分:0)
正如放松所说,问题在于strtok()
。我认为你的代码有一些未定义的行为,因为你使用了delimiter参数错误。
令牌strtok将会发现:43,0000,0000,043,8,21.45,45.65,9.34,3.46 我甚至不知道为什么它能为你提取T,HR等等。
如果您删除了多次分配给它的分隔符并再次计算代码,那么将会有一个有效的(根本不优雅)解决方案。
检查代码和输出HERE
答案 2 :(得分:0)
在此之前得到了帮助,我觉得我有责任介入并尝试整理我的代码,这些代码已经停止了它应该做的事情:)
好的,我建议您输入两个单独的案例,我将它们拆分为以'+'开头的'+''和'N'开头的'Nodo_8'(这是非常原始的,请确保确实如此,否则有一些进一步的验证。)
我已经从循环开始到最后将调用移动到strok
,因为在我们有机会提取任何内容之前,它可能在第一次迭代时将字符串“标记”两次。我在递增i
之前就把它放了。如果你想在开始时保持它,只需从我们进行检查的i
中减去1。
然后,只需要找出循环的哪个迭代就会吐出正确的值。
#include <stdio.h>
#include <string.h>
int main()
{
/* dev_a and dev_b could be the same source in your case, modify accordingly */
char dev_a[] = "+DATA: 43 BYTES FROM 0000:0000 (043)";
char dev_b[] = "Nodo_8:(T=21.23,HR=42.65,DW=9.45,Vcc=3.46V)";
char out0[35] = "";
char out1[35] = "";
char out2[35] = "";
char out3[35] = "";
char out4[45] = "";
char* ptr;
int i;
if (dev_a[0] == '+')
{
ptr = strtok(dev_a, "+DATA: BYTES FROM ()");
i = 0;
while (ptr != NULL)
{
if (i == 3)
strcat(out0, ptr); /* copies DATA (value in brackets) */
ptr = strtok(NULL, "+DATA: BYTES FROM ()");
i++;
}
printf("+DATA: %s\n", out0);
}
if (dev_b[0] == 'N')
{
ptr = strtok(dev_b, "Nodo_,=T:HR:DW:Vcc()");
i = 0;
while (ptr != NULL)
{
if (i == 1)
strcat(out1, ptr); /* copies T */
if (i == 2)
strcat(out2, ptr); /* copies HR */
if (i == 3)
strcat(out3, ptr); /* copies DW */
if (i == 4)
strcat(out4, ptr); /* copies Vcc */
ptr = strtok(NULL, "Nodo_,=T:HR:DW:Vcc()");
i++;
}
printf("Nodo_8: %s, %s, %s, %s\n", out1, out2, out3, out4);
}
return 0;
}
使用此代码,我得到以下输出(所有三种情况都为'Nodo'):
$ ./a.out
+DATA: 043
Nodo_8: 21.45, 45.65, 9.34, 3.46
$ ./a.out
+DATA: 043
Nodo_8: 21.67, 42.45, 9.23, 3.46
$ ./a.out
+DATA: 043
Nodo_8: 21.23, 42.65, 9.45, 3.46
'043'对应'+ DATA'部分,其余部分对应'Nodo'位。
我有正确的价值吗?我从你的帖子做了一个假设。我已经测试了你提供的所有三个'Nodo'样品。
答案 3 :(得分:0)
可能,我认为buff包含你不期望的隐藏字符。
所以,我想我需要添加一个过程来摆脱buff
中的隐藏字符。
E.g。
#include <ctype.h>
void strip_nonprint(char s[]) {
char *from, *to;
from = to = s;
while(*from){
if(isprint(*from))//note: remove newline
*to++ = *from++;
else
++from;
}
*to = '\0';
}
更改代码:
n=read(fd,buff,83);
strip_nonprint(buff);//add
/* { i | 2, 4, 5, 6, 7} */
if (i == 2)
strcat(dev_a, ptr); // copies device
if (i == 4)
strcat(temp_a, ptr); // copies T
if (i == 5)
strcat(hr_a, ptr); // copies HR
if (i == 6)
strcat(dw_a, ptr); // copies DW
if (i == 7)
strcat(vcc_a, ptr);