-1

有没有更好的解析下面的字符串而不是做 astrtok()来获取每个字段。

“主题=什么&cc=bose@yahoo.com&server=smtp.yahoo.com:8000”

基本上我想将每个字段的值检索到另一个 char buf 中。

这是我的代码。只是想知道是否还有其他更好的方法(任何更好的字符串解析算法)

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

#define SUBJECT "subject="
#define CC_LIST "cc="
#define SERVER "server="

static void
get_value (const char *tok, char **rval_buf, size_t field_len)
{
    size_t val_size = 0;

    if (!tok || !rval_buf)
        return;

    val_size = strlen(tok + field_len) + 1;
    *rval_buf = calloc(1, val_size);

    if (*rval_buf) {
        strlcpy(*rval_buf, tok + field_len, val_size);
    }
}


int
main (int argc, char **argv)
{
    /* hard coded buf for testing */
    char buf[] = "subject=what&cc=bose@yahoo.com&server=smtp.yahoo.com:8000";
    char *subject_text = NULL;
    char *cc_list = NULL;
    char *server_addr = NULL;
    char *tok = NULL;
    int field_len = 0;
    int val_len = 0;

    tok = strtok(buf, "&");
    while(tok) {
        /*
         * Handle the token
         */
        /* check if it is subject */
        if (strstr(tok, SUBJECT)) {
            get_value(tok, &subject_text, strlen(SUBJECT));
        } else if (strstr(tok, CC_LIST)) { /* check if it is CC */
            get_value(tok, &cc_list, strlen(CC_LIST));
        } else if (strstr(tok, SERVER)) { /* check if it is server */
            get_value(tok, &server_addr, strlen(SERVER));
        }
        tok = strtok(NULL, "&");
    }
    /* dump data */
    fprintf(stdout, "\nSUBJECT: \"%s\"\nCC_LIST: \"%s\"\nSERVER: \"%s\" \n\n",
            subject_text, cc_list, server_addr);

    return EXIT_SUCCESS;
}
4

3 回答 3

1

strstr在另一个字符串(“the haystack”)中搜索一个字符串(“the needle”),但您真的只想知道该 needle 是否是 haystack 的开头。

这是一个小建议:(需要#include <stdbool>或将布尔值更改为整数。我喜欢布尔值。)

static bool
getval(const char* haystack, const char** res, const char* needle, size_t len) {
  if (haystack && 0 == strncmp(haystack, needle, len)) {
    *res = strdup(haystack + len);
    return true;
  }
  return false;
}

然后:

for (tok = strtok(buf, "&"); tok; tok = strtok(NULL, "&")) {
  getval(tok, &subject_text, SUBJECT, strlen(SUBJECT)) ||
  getval(tok, &cc_list, CC_LIST, strlen(CC_LIST)) ||
  getval(tok, &server_addr, SERVER, strlen(SERVER));
}

实际上,您可以不用做strleninside of getval,这大大减少了噪音,因为大多数现代编译器都足够聪明,可以内联 getval 并对常量字符串的长度进行常量折叠。

于 2013-10-01T20:46:56.223 回答
0

我为你写了一个快速-n-脏分离器:

int split(char* input, char delim, char*** parts)
{
    int count = 1;
    char** result;
    char* t = input;
    while(*t != '\0')
    {
        if (*t++ == delim)
        {
            count++;
        }
    }

    result = (char**)malloc(count * sizeof(char*));

    t = input;
    int i = 0;
    result[i] = input;
    while(*t != '\0')
    {
        if (*t == delim)
        {
            *t = '\0';
            result[++i] = ++t;
        }
        else
        {
            t++;
        }
    }
    *parts = result;
    return count;
}

int main()
{
    char raw[] = "subject=\"some text\"&cc=abcd&server=acd.com";
    char* str = _strdup(raw);
    char** parts;
    char** keyval;
    int cnt = split(str, '&', &parts);
    for(int i=0; i<cnt; ++i)
    {
        split(parts[i], '=', &keyval);
        printf("[%d]: %s <--> %s\n", i, keyval[0], keyval[1]);
        free(keyval);
    }
    free(parts);

    getchar();
    return 0;
}

输出

[0]: subject <--> "some text"
[1]: cc <--> abcd
[2]: server <--> acd.com
于 2013-10-01T19:39:41.467 回答
0

使用 strtok()

char *strtok(char *str, const char *delim)

您可以将 '&' 作为分隔符

于 2013-10-01T19:29:52.050 回答