【问题标题】:Split string with strtok (nested)使用 strtok 拆分字符串(嵌套)
【发布时间】:2018-07-25 17:58:38
【问题描述】:

我使用 arduino MEGA 来解析 url 的参数部分。 参数的顺序如何无关紧要。我有以下代码,我用 strtok 尝试过。

char text[] = "ssid=SSID&pwd=PASSWORD&userId=1234"

会分裂

ssid=SSID
pwd=PASSWORD
userId=1234

并再次将其拆分为键和值

ssid
SSID

pwd
PASSWORD

userId
1234

我尝试使用 strtok 进行第一次拆分。

  char *ptr;
  ptr = strtok(params, "&");

  while (ptr != NULL) {
    Serial.println(urlParam);
    ptr = strtok(NULL, "&");
  }

输出如预期:

输出:

ssid=SSID
pwd=PASSWORD
userId=1234

然后下一个拆分:

  char *ptr;
  ptr = strtok(params, "&");

  while (ptr != NULL) {

    char *paramKey;
    char *paramValue;
    paramKey = strtok(ptr, "=");
    Serial.println(paramKey);

    if (paramKey == 'ssid'){
      paramValue = strtok(NULL, "=");
      Serial.println(paramValue);       

      ssidName = paramValue;
    }

    if (paramKey == 'pwd'){
      ...
    }

    if (paramKey == 'userId'){
      ...
    }       

    ptr = strtok(NULL, "&");
  }

但输出只是

ssid
SSID

看起来循环工作不正常。

我在哪里犯了错误? 有没有其他方法可以解决这个字符串?

【问题讨论】:

  • 你不能像这样在不同的 strtok 目标之间来回切换——你必须在再次使用 strtok 之前完成所有第一个 strtok。

标签: c++ arduino


【解决方案1】:

strtok 函数使用内部静态变量来跟踪其当前状态。当您将函数用于像您正在做的那样交错的多个不同子字符串时,您会踩到内部状态。

您需要改用strtok_r,它使用外部变量来跟踪状态。

  char *ptr, *sav1 = NULL;
  ptr = strtok_r(params, "&", &sav1);    // outer strtok_r, use sav1

  while (ptr != NULL) {

    char *paramKey;
    char *paramValue;
    char *sav2 = NULL;
    paramKey = strtok_r(ptr, "=", &sav2);   // inner strtok_r, use sav2
    Serial.println(paramKey);

    if (!strcmp(paramKey, "ssid")) {
      paramValue = strtok_r(NULL, "=", &sav2);  // inner strtok_r, use sav2
      Serial.println(paramValue);       

      ssidName = paramValue;
    }

    if (!strcmp(paramKey, "pwd")) {
      ...
    }

    if (!strcmp(paramKey, "userId")) {
      ...
    }       

    ptr = strtok_r(NULL, "&", &sav1);    // outer strtok_r, use sav1
  }

与解析问题无关,您也无法将字符串与== 进行比较。您需要改用strcmp,字符串常量用双引号括起来,而不是单引号。

【讨论】:

  • 该解决方案效果很好。非常感谢!!! strcmp 我应该知道,我的错误。 Strtok_r 对我来说是新的,所以我必须阅读更多关于它的内容。
【解决方案2】:

你有三个问题:

  1. 首先是您使用特定于实现的多字符文字,例如'ssid',当你应该使用像 "ssid" 这样的字符串时。

  2. 第二个问题是你使用==来比较字符串。这几乎是不可能的,因为然后你比较 pointers 而不是字符串内容。要比较字符串,您需要使用strcmp

  3. strtok 函数不可重入。您不能同时进行多个 strtok 解析。要么分开步骤,要么使用strtok_s(或strtok_r,如果有这样的功能)。

【讨论】:

  • 或者根本不要使用strtokfamily。分割字符串有很多更好的方法。
【解决方案3】:
#include <stdio.h>
#include <string.h>

struct split_result {
    char first_part[64];
    char second_part[64];
};

split_result return_left(char splitter, const char *str);

int main() {
    /*
        ssid=SSID
        pwd=PASSWORD
        userId=1234
    */
    char *str = "ssid=109304905995";
    split_result result = return_left('=', str);

    printf("first part: %s \n second part: %s\n", result.first_part, result.second_part);

    return 0;
}

split_result return_left(char splitter, const char *str) {
    int i = 0;

    split_result split_ptr;

    while (str[i] != 0) {
        //we found splitter
        if ((char)str[i] == splitter) {
            //remove first half
            strncpy_s(split_ptr.first_part, str, (int)(&str[i]-str));
            break;
        }

        //we need to remove second half now
        i++;
    }
    strcpy_s(split_ptr.second_part, &str[i+1]);
    return split_ptr;
}

我希望这对任何人都有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多