打印

模仿http解析方式写了一个函数,看看吧,有趣哟~

[复制链接]
1707|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
japrincess|  楼主 | 2011-12-7 21:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
问题:
[{"iconNo":"1","seq":"1","devStatus":"1","devdescribe":"asd"}]

[{"iconNo":"2","seq":"2","devStatus":"2","devdescribe":"asasdsasdas师大d"}]

解析出各个字段,得到key-value。

我看Lighttpd解析http那一块代码大约1000行,不过它里边包括了http协议的处理,这里特意为了模仿它,写了一个基本类似的函数。

说说我为什么要写这么长吧, 因为我假设用户的输入是任意风格的, 也就是会有很多地方敲一些空格或者TAB, 格式也比较乱, 这里我还没有处理折叠格式,写时候忘了搞了,无非就是特殊对待一下\n。  

http里的"\r\n" 对应这里的','。
另外,这里由于这里的key,value都被""包裹,我假定""内不允许存在空白字符,对于http,需要特殊判断key中间是否有空白字符。

这个办法靓点在哪里呢? 就是一趟扫描,不需要回溯再去检查合法性,那么复杂的情况为何可以做到呢? 就是用了state这个变量, 将解析过程划分成了不同的阶段, 0阶段是解析一行第一次进入的状态,以后都不会再进入了, 1是解析key,2是解析:并且过度到3阶段,3阶段是解析val,4阶段是解析,或者行结尾。 通过state,保证每一个case里我们完全把精力集中在一部分,简化了逻辑复杂性,希望大家有所体会。


owenliang@linux-7lsl:~/csdn/src> ./main
iconNo:
1
seq:
1
devStatus:
1
devdescribe:asd
iconNo:
2
seq:
2
devStatus:
2
devdescribe:asasdsasdas师大d

相关帖子

沙发
japrincess|  楼主 | 2011-12-7 21:50 | 只看该作者
C/C++ code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static const char* parse_test[] =
{
    "[{\"iconNo\":\"1\",\"seq\":\"1\",\"devStatus\":\"1\",\"devdescribe\":\"asd\"}]",
    "[{\"iconNo\":\"2\",\"seq\":\"2\",\"devStatus\":\"2\",\"devdescribe\":\"asasdsasdas师大d\"}]"
};

int parse_key_value(const char *line)
{
    // 主要检查以下不合法性:
    //1, key或者value没有被'"'包裹
    //2, ""内没有空白字符
    //3, key : value 形式不合法

    int key_start, dot, key_end, val_start, val_end;
    int line_len;
    int state = 0;    //0:初始化,1:解析key,2:解析',',3:解析val,4:解析',' or '\0'
                    //or }]序列
    int left_over = 0;
    char key[20], value[30];

    key_start = dot = key_end = val_start = val_end = -1;
    line_len = strlen(line);
   
    for (int i = 0; i <= line_len; /*<=line_len目的: 对','和'\0'同等对待*/)
    {
        switch (state)
        {
            case 0:
            {
                switch (line[i])
                {
                    case ' ':
                    case '\t':
                    {
                        ++i;
                    }break;
                    case '[':
                    {
                        // 多余的[
                        if (left_over != 0)
                        {
                            return -1;
                        }

                        if (line[i+1] != '{')
                        {
                            return -1;
                        }

                        left_over++; //左侧"[{"序列合法
                        i+=2;
                    }break;
                    case '{':    //不应该单独出现,此分支可以不写,被default处理
                    {
                        return -1;
                    }break;
                    case '"':
                    {
                        if (left_over == 0)
                        {
                            //还没遇到[{序列
                            return -1;
                        }
                        // key的左'"',记录key_start
                        key_start = ++ i;
                        ++ state; //进入解析key状态
                    }break;
                    default:
                    {   
                        // 非空白字符 or 非[{序列 or 非'"' or '\0'
                        return -1;
                    };
                }
            }break;
            case 1:
            {
                switch (line[i])
                {
                    case ' ':
                    case '\t':
                    case '{':
                    case '[':
                    case ',':
                    case ':':
                    case '\0':
                    {
                        // key不应该包含非字母,这里只列举一些
                        return -1;
                    }break;
                    case '"':
                    {
                        //key结束,记录key_end
                        key_end = i-1;

                        if (key_end < key_start)    //key为空
                        {
                            return -1;
                        }

                        ++ i;
                        state ++; // 进入解析':'状态
                    }break;
                    default:
                    {
                        // 任意合法字母
                        ++ i;
                    }break;
                }
            }break;
            case 2:
            {
                switch (line[i])
                {
                    case '\t':
                    case ' ':
                    {
                        // 空白字符掠过
                        ++ i;
                    }break;
                    case ':':
                    {
                        //找到':'
                        dot = i++;
                        state++;

                        //向后掠过所有的空白,检测"val的'"'

                        while (line[i] != '\0')
                        {
                            if (line[i] != ' ' && line[i] != '\t')
                            {
                                if (line[i] != '"')
                                {
                                    return -1;    //遇到非空白非"字符
                                }

                                val_start = ++ i;
                                break;
                            }
                           
                            ++ i;
                        }

                        if (val_start == -1)
                        {
                            return -1;
                        }
                    }break;
                    default:
                    {
                        //非合法,出错
                        return -1;
                    }break;
                }
            }break;
            case 3:    //开始解析value
            {
                switch (line[i])
                {
                    //val内不应该有非字母字符
                    case '\t':
                    case ' ':
                    case ',':
                    case '\0':
                    case '[':
                    case '}':
                    case ']':
                    case '{':
                    {
                        return -1;
                    }break;
                    case '"':
                    {
                        val_end = i - 1;
                        
                        if (val_end < val_start)
                        {
                            return -1;
                        }

                        ++ i;
                        state++;
                    }break;
                    default:
                    {
                        ++ i;    //正常字母
                    }break;
                }
            }break;
            case 4:    //最后阶段:如果是line末尾需要检测}]
                    //不是line末尾需要检测',',并且重新进入state = 1
            {
                // 直接快速的处理过去

                while (line[i] == ' ' || line[i] == '\t')
                {
                    ++ i;
                }

                if (line[i] == '\0')
                {
                    return -1; // line末尾,却没有}]
                }

                if (line[i] == ',')
                {
                    // 一个字段结束,打印key,value
                    strncpy(key, line + key_start, key_end - key_start + 1);
                    key[key_end - key_start + 1] = '\0';
                    strncpy(value, line + val_start, val_end - val_start + 1);
                    value[val_end - val_start + 1] = '\0';
                    printf("%s:%s\n", key, value);
                    key_start = key_end = val_start = val_end = -1;
                    
                    // 向后找到value的"
                    while (line[++i] != '\0' && (line[i] == ' ' || line[i] == '\t'));
                    
                    if (line[i] != '"')
                    {
                        return -1;     // , 之后非",错误
                    }

                    key_start = ++ i;
                    state = 1;    //直接进入解析value状态
                }
                else if (line[i] == '}')
                {
                    if (line[i+1] != ']')
                    {
                        return -1;    //}]不完整
                    }
                    
                    strncpy(key, line + key_start, key_end - key_start + 1);
                    key[key_end - key_start + 1] = '\0';
                    strncpy(value, line + val_start, val_end - val_start + 1);
                    value[val_end - val_start + 1] = '\0';
                    printf("%s:%s\n", key, value);

                    return 0;    //解析完毕,}]之后再有字符也不理会了
                }
                else
                {
                    // 意外的字符
                    return -1;
                }
            }break;
            default:
            {
                fprintf(stderr, "unknown state %d \n", state);
                return -1;
            }break;
        }
    }
}

int main()
{
    char test_buffer[1000];

    while (scanf("%s", test_buffer) == 1)
    {
        parse_key_value(test_buffer);
    }

    for (int i = 0; i < 2; ++ i)
    {
        parse_key_value(parse_test[i]);
    }
    return 0;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

249

帖子

1

粉丝