用strtok分割字符串(嵌套)

时间:2018-07-25 17:58:38

标签: c++ arduino

我使用arduino MEGA解析网址的参数部分。 参数的顺序无关紧要。我有以下代码,并使用strtok进行了尝试。

log4j-api-2.11.0.jar

并将拆分

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

并再次将其拆分为键和值

ssid=SSID
pwd=PASSWORD
userId=1234

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

ssid
SSID

pwd
PASSWORD

userId
1234

并且输出符合预期:

输出:

  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, "&");
  }

看起来循环无法正常工作。

我在哪里犯错? 还有其他解决此字符串的方法吗?

4 个答案:

答案 0 :(得分:3)

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,字符串常量用双引号而不是单引号引起来。

答案 1 :(得分:1)

您有三个问题:

  1. 第一个是您使用特定于实现的多字符文字,例如'ssid',应使用"ssid"之类的字符串。

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

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

如果输入始终为key=value&...key=value,则可以遍历字符串并使用strtok捕获每个键和值。

#include <stdio.h>
#include <string.h>

int main ( void) {
    char text[] = "ssid=SSID&pwd=PASSWORD&userId=1234";
    char *key = NULL;
    char *value = NULL;
    char *ssidName = NULL;
    char *pwdName = NULL;
    char *useridName = NULL;

    key = strtok(text, "=");//first key
    while ( key) {
        printf ( "\nkey %s\n", key);
        value = strtok(NULL, "&");//value between = and &
        if ( !strcmp ( key, "ssid")) {
            if ( value) {
                ssidName = value;
                printf ( "value %s\n", ssidName);
            }
        }
        if ( !strcmp ( key, "pwd")) {
            if ( value) {
                pwdName = value;
                printf ( "value %s\n", pwdName);
            }
        }
        if ( !strcmp ( key, "userId")) {
            if ( value) {
                useridName = value;
                printf ( "value %s\n", useridName);
            }
        }
        key = strtok(NULL, "=");//next key
    }
    return 0;
}

请注意,指针*Name指向text中的某个位置。如果text被覆盖,则这些指针将不再指向其先前的值。在这种情况下,请为指针分配内存并复制内容。