在C语言中优雅地解析查询字符串

7
我正在尝试在C语言中解析URL查询字符串,不知道如何优雅地实现。如果有任何提示或建议,将不胜感激:
static void readParams(char * string, char * param, char * value) {
    char arg[100] = {0};  // Not elegant, brittle
    char value2[1024] = {0};

    sscanf(string, "%[^=]=%s", arg, value2);
    strcpy(param, arg);
    strcpy(value, value2);
}
char * contents = "username=ted&age=25";
char * splitted = strtok (contents,"&");
char * username;
char * age;

while (splitted != NULL)
{
    char param[100]; // Not elegant, brittle
    char value[100];
    char * t_str = strdup(splitted);
    readParams(t_str, param, value);
    if (strcmp(param, "username") == 0) {
        username = strdup(value);
    }
    if (strcmp(param, "age") == 0) {
        age = strdup(value); // This is a string, can do atoi
    }
   splitted = strtok (NULL, "&");
 }

我一直遇到的问题是,由于strtok 函数的存在,在最后一个 strtok 函数之前进行任何看起来更加智能的操作似乎都会导致while循环中断。

问题是什么?也许是我英语不好,但我不明白代码的哪一部分困扰了你以及为什么。 - Petr Abdulin
这并不是什么麻烦的事情,而是代码依赖于一些假设(比如值和参数小于100)使得它不够优雅。 - Rio
4个回答

2

你要么需要定制复杂而有效的解析器,要么就使用现成的库来为你完成。

uriparser 库应该能提供你所需的一切(而且支持 Unicode)。


2

我做:

    char querystring[]="a=1&b&c=3&d=&meh=5";
    int pc=0;
    char *tok;
    char *otok;
    for(tok=strtok(querystring,"&");tok!=NULL;tok=strtok(tok,"&")) {
        pc++;
        otok=tok+strlen(tok)+1;
        tok=strtok(tok,"=");
        fprintf(stderr,"param%d: %s ",pc,tok);
        tok=strtok(NULL,"=");
        fprintf(stderr,"value%d: %s\n",pc,tok);
        tok=otok;
    };

记住,strtok会破坏原始数据,所以在这之前请先复制查询字符串。


1
通常情况下,strtok会将源字符串分解为其他函数使用。以下是使用strtok对字符串进行标记化的基本示例。
  #include <stdlib.h>
  #include <string.h>
  #include <stdio.h>
  #define MX_SPLIT 128
    char **split( char **result, char *working, const char *src, const char *delim)
    {
        int i;

        strcpy(working, src); // working will get chppped up instead of src 
        char *p=strtok(working, delim);
        for(i=0; p!=NULL && i < (MX_SPLIT -1); i++, p=strtok(NULL, delim) )
        {
            result[i]=p;
            result[i+1]=NULL;  // mark the end of result array
        }
        return result;
    }

    void foo(const char *somestring)
    {
       int i=0;
       char *result[MX_SPLIT]={NULL};
       char working[256]={0x0}; // assume somestring is never bigger than 256 - a weak assumption
       char mydelim[]="!@#$%^&*()_-";
       split(result, working, somestring, mydelim);
       while(result[i]!=NULL)
          printf("token # %d=%s\n", i, result[i]);
    }

0

假设并不是一件坏事,尤其是在编写快速、强大和保护性代码时(例如,考虑您的输入字符串格式无效的情况)。

然而,为了实现最具弹性的代码,您需要手动分配(并在使用后释放!)字符串的内存,其大小应该是输入字符串的总长度(在合理限制下再加一次),因为通常情况下不知道参数和值字符串部分的长度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接