Мне нужно сочетание strtok и strtok_single

У меня есть следующая строка, которую я пытаюсь проанализировать для переменных.

char data[]="to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards." 

Я начал с strtok и следующего кода

 char *to=parsePostData("to",data); char* parsePostData(char s[],char t[]) { char *postVal; char *pch; char tCpy[512];//Make a copy. Otherwise, strtok works on the char pointer, and original char array gets modified/ corrupted. strcpy(tCpy,t); pch = strtok (tCpy,"=&"); while (pch != NULL) { if(strcmp(pch,s)==0) { pch= strtok (NULL, "&"); return pch; }else{ pch = strtok (NULL, "=&"); } } } 

Это прекрасно работает, за исключением случаев, когда речь идет о последовательных разделителях, таких как «title». Поэтому я нашел эту обычную реализацию strtok_single. Необходимо знать, когда между двумя разделителями токенов нет данных, используя strtok ()

 char * strtok_single (char * str, char const * delims) { static char * src = NULL; char * p, * ret = 0; if (str != NULL) src = str; if (src == NULL) return NULL; if ((p = strpbrk (src, delims)) != NULL) { *p = 0; ret = src; src = ++p; } return ret; } 

Но с этим проблема заключается в том, что я не могу получить «подпись», так как после этого не существует & разделителя.

Как я могу получить сочетание этих двух, поэтому я не пропущу последнюю переменную, и я могу обрабатывать последовательные разделители?

Здесь есть две ошибки. Один из них находится в strtok_single() . Если вы запустите его несколько раз, он не возвращает последний сегмент, после = после подписи, в отличие от strtok() .

Когда это исправлено, все еще существует проблема с кодом в parsePostData() ; он возвращает указатель на автоматическую переменную. Копировать строку нужно обрабатывать по-разному; самый простой способ (который согласуется с использованием strtok() а не strtok_r() или strtok_s() ), чтобы сделать переменную tCpy статической.

Тест-программа emt.c

Это сложная программа, которая показывает проблемы, а также набор исправлений. Он применяет различные функции «сплиттера» – функции с той же сигнатурой, что и strtok() – к данным. Он демонстрирует ошибку в strtok_single() и strtok_fixed() исправляет эту ошибку. Он демонстрирует, что код в parsePostData() работает правильно, когда он исправлен, и используется strtok_fixed() .

 #include  #include  /* Function pointer for strtok, strtok_single, strtok_fixed */ typedef char *(*Splitter)(char *str, const char *delims); /* strtok_single - as quoted in SO 30294129 (from SO 8705844) */ static char *strtok_single(char *str, char const *delims) { static char *src = NULL; char *p, *ret = 0; if (str != NULL) src = str; if (src == NULL) return NULL; if ((p = strpbrk(src, delims)) != NULL) { *p = 0; ret = src; src = ++p; } return ret; } /* strtok_fixed - fixed variation of strtok_single */ static char *strtok_fixed(char *str, char const *delims) { static char *src = NULL; char *p, *ret = 0; if (str != NULL) src = str; if (src == NULL || *src == '\0') // Fix 1 return NULL; ret = src; // Fix 2 if ((p = strpbrk(src, delims)) != NULL) { *p = 0; //ret = src; // Unnecessary src = ++p; } else src += strlen(src); return ret; } /* Raw test of splitter functions */ static void parsePostData1(const char *s, const char *t, Splitter splitter) { static char tCpy[512]; strcpy(tCpy, t); char *pch = splitter(tCpy, "=&"); while (pch != NULL) { printf(" [%s]\n", pch); if (strcmp(pch, s) == 0) printf("matches %s\n", s); pch = splitter(NULL, "=&"); } } /* Fixed version of parsePostData() from SO 30294129 */ static char *parsePostData2(const char *s, const char *t, Splitter splitter) { static char tCpy[512]; strcpy(tCpy, t); char *pch = splitter(tCpy, "=&"); while (pch != NULL) { if (strcmp(pch, s) == 0) { pch = splitter(NULL, "&"); return pch; } else { pch = splitter(NULL, "=&"); } } return NULL; } /* Composite test program */ int main(void) { char data[] = "to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards."; char *tags[] = { "to", "cc", "title", "content", "signature" }; enum { NUM_TAGS = sizeof(tags) / sizeof(tags[0]) }; printf("\nCompare variants on strtok()\n"); { int i = NUM_TAGS - 1; printf("strtok():\n"); parsePostData1(tags[i], data, strtok); printf("strtok_single():\n"); parsePostData1(tags[i], data, strtok_single); printf("strtok_fixed():\n"); parsePostData1(tags[i], data, strtok_fixed); } printf("\nCompare variants on strtok()\n"); for (int i = 0; i < NUM_TAGS; i++) { char *value1 = parsePostData2(tags[i], data, strtok); printf("strtok: [%s] = [%s]\n", tags[i], value1); char *value2 = parsePostData2(tags[i], data, strtok_single); printf("single: [%s] = [%s]\n", tags[i], value2); char *value3 = parsePostData2(tags[i], data, strtok_fixed); printf("fixed: [%s] = [%s]\n", tags[i], value3); } return 0; } 

Пример вывода из emt

 Compare variants on strtok() strtok(): [to] [myself@gmail.com] [cc] [youself@gmail.com] [title] [content] [how are you?] [signature] matches signature [best regards.] strtok_single(): [to] [myself@gmail.com] [cc] [youself@gmail.com] [title] [] [content] [how are you?] [signature] matches signature strtok_fixed(): [to] [myself@gmail.com] [cc] [youself@gmail.com] [title] [] [content] [how are you?] [signature] matches signature [best regards.] 

А также:

 Compare variants on strtok() ✓ strtok: [to] = [myself@gmail.com] ✓ single: [to] = [myself@gmail.com] ✓ fixed: [to] = [myself@gmail.com] ✓ strtok: [cc] = [youself@gmail.com] ✓ single: [cc] = [youself@gmail.com] ✓ fixed: [cc] = [youself@gmail.com] ✕ strtok: [title] = [content=how are you?] ✓ single: [title] = [] ✓ fixed: [title] = [] ✓ strtok: [content] = [how are you?] ✓ single: [content] = [how are you?] ✓ fixed: [content] = [how are you?] ✓ strtok: [signature] = [best regards.] ✕ single: [signature] = [(null)] ✓ fixed: [signature] = [best regards.] 

Правильные (✓ = U + 2713) и неправильные отметки (✕ = U + 2715) были добавлены вручную при отправке ответа.

Наблюдайте, как только строки, помеченные как «фиксированные», содержат точно то, что требуется каждый раз.

Вы точно не сказали нам, что вы подразумеваете под «это прекрасно работает», хотя кажется достаточным сказать, что вы хотите разобрать строку application/x-www-form-urlencoded . Почему ты не сказал это в первую очередь?

Учтите, что первое поле, key , может быть прервано первым из '=' или '&' . Было бы целесообразно искать токен, который заканчивается одним из этих символов, для извлечения key .

Второе поле, value , однако, не прерывается символом '=' , поэтому неуместно искать этот символ для извлечения value . Вы хотите искать только '&' .

Конечно. Вы можете использовать strtok для синтаксического анализа этого, но я уверен, что есть еще много подходящих инструментов. strcspn , strcspn не будет вносить никаких изменений в data , а это значит, что вам не нужно будет делать копию data как вы …

 #include  #include  int main(void) { char data[]="to=myself@gmail.com&cc=youself@gmail.com&title=&content=how are you?&signature=best regards."; char *key = data; do { int key_length = strcspn(key, "&="); char *value = key + key_length + (key[key_length] == '='); int value_length = strcspn(value, "&"); printf("Key: %.*s\n" "Value: %.*s\n\n", key_length, key, value_length, value); key = value + value_length + (value[value_length] == '&'); } while (*key); return 0; }