【问题标题】:strange tokens results using strtok使用 strtok 产生奇怪的标记
【发布时间】:2013-06-03 08:27:54
【问题描述】:

我的外部设备每 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

等等。 有谁知道问题出在哪里,我在 051 之前有 3.46? strtok有什么问题吗? 我的结果希望为 043、21.67、42.45、9.23、3.46

【问题讨论】:

    标签: c token strtok


    【解决方案1】:

    我相信你误解了strtok() 的第二个参数;它不是一个完整的分隔符字符串,它是一个“字符集”。换句话说,字符串中的每个字符都被认为是一个有效的分隔符。

    查看the manual page了解更多详情,注意上面写着:

    delim 参数指定一组字节,用于分隔已解析字符串中的标记。

    一般来说,这看起来应该用一个普通的sscanf() 来解决,不需要使用strtok(),这有点低级和棘手。

    【讨论】:

      【解决方案2】:

      之前在这方面提供过帮助,我觉得我有责任介入并尝试整理我的代码,这些代码已经停止做它应该做的事情:)

      好的,我建议您输入两个单独的案例,我将它们分成以“+”开头的“+DATA”和“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】:

        正如 unwind 所说,问题出在strtok() 上。我认为您的代码做出了一些未定义的行为,因为您使用了错误的 delimiter 参数。

        strtok 将找到的令牌将是:43,0000,0000,043,8,21.45,45.65,9.34,3.46 我什至不知道为什么提取 T、HR 等对你有用。

        如果您删除了多次给它的分隔符并再次计算令牌,那么将有一个可行的(根本不优雅)解决方案。

        检查代码和输出HERE

        【讨论】:

          【解决方案4】:

          可能,我认为 buff 包含了你没想到的隐藏字符。

          所以,我想我需要添加一个进程来消除 buff 中的隐藏字符。

          例如

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

          【讨论】:

            猜你喜欢
            • 2021-10-20
            • 2011-05-08
            • 1970-01-01
            • 1970-01-01
            • 2018-12-27
            • 1970-01-01
            • 2015-07-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多