找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 4081|回复: 0

一趟解析处理http

[复制链接]
发表于 2011-12-3 11:50:52 | 显示全部楼层 |阅读模式
来自:http://topic.csdn.net/u/20111128/14/d701ae5b-b6a3-45ff-a199-d068d77ecb5d.html
问题:
[{"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里我们完全把精力集中在一部分,简化了逻辑复杂性,希望大家有所体会。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. static const char* parse_test[] =
  5. {
  6.     "[{"iconNo":"1","seq":"1","devStatus":"1","devdescribe":"asd"}]",
  7.     "[{"iconNo":"2","seq":"2","devStatus":"2","devdescribe":"asasdsasdas师大d"}]"
  8. };
  9. int parse_key_value(const char *line)
  10. {
  11.     // 主要检查以下不合法性:
  12.     //1, key或者value没有被'"'包裹
  13.     //2, ""内没有空白字符
  14.     //3, key : value 形式不合法
  15.     int key_start, dot, key_end, val_start, val_end;
  16.     int line_len;
  17.     int state = 0;    //0:初始化,1:解析key,2:解析',',3:解析val,4:解析',' or '\0'
  18.                     //or }]序列
  19.     int left_over = 0;
  20.     char key[20], value[30];
  21.     key_start = dot = key_end = val_start = val_end = -1;
  22.     line_len = strlen(line);
  23.    
  24.     for (int i = 0; i <= line_len; /*<=line_len目的: 对','和'\0'同等对待*/)
  25.     {
  26.         switch (state)
  27.         {
  28.             case 0:
  29.             {
  30.                 switch (line[i])
  31.                 {
  32.                     case ' ':
  33.                     case '\t':
  34.                     {
  35.                         ++i;
  36.                     }break;
  37.                     case '[':
  38.                     {
  39.                         // 多余的[
  40.                         if (left_over != 0)
  41.                         {
  42.                             return -1;
  43.                         }
  44.                         if (line[i+1] != '{')
  45.                         {
  46.                             return -1;
  47.                         }
  48.                         left_over++; //左侧"[{"序列合法
  49.                         i+=2;
  50.                     }break;
  51.                     case '{':    //不应该单独出现,此分支可以不写,被default处理
  52.                     {
  53.                         return -1;
  54.                     }break;
  55.                     case '"':
  56.                     {
  57.                         if (left_over == 0)
  58.                         {
  59.                             //还没遇到[{序列
  60.                             return -1;
  61.                         }
  62.                         // key的左'"',记录key_start
  63.                         key_start = ++ i;
  64.                         ++ state; //进入解析key状态
  65.                     }break;
  66.                     default:
  67.                     {   
  68.                         // 非空白字符 or 非[{序列 or 非'"' or '\0'
  69.                         return -1;
  70.                     };
  71.                 }
  72.             }break;
  73.             case 1:
  74.             {
  75.                 switch (line[i])
  76.                 {
  77.                     case ' ':
  78.                     case '\t':
  79.                     case '{':
  80.                     case '[':
  81.                     case ',':
  82.                     case ':':
  83.                     case '\0':
  84.                     {
  85.                         // key不应该包含非字母,这里只列举一些
  86.                         return -1;
  87.                     }break;
  88.                     case '"':
  89.                     {
  90.                         //key结束,记录key_end
  91.                         key_end = i-1;
  92.                         if (key_end < key_start)    //key为空
  93.                         {
  94.                             return -1;
  95.                         }
  96.                         ++ i;
  97.                         state ++; // 进入解析':'状态
  98.                     }break;
  99.                     default:
  100.                     {
  101.                         // 任意合法字母
  102.                         ++ i;
  103.                     }break;
  104.                 }
  105.             }break;
  106.             case 2:
  107.             {
  108.                 switch (line[i])
  109.                 {
  110.                     case '\t':
  111.                     case ' ':
  112.                     {
  113.                         // 空白字符掠过
  114.                         ++ i;
  115.                     }break;
  116.                     case ':':
  117.                     {
  118.                         //找到':'
  119.                         dot = i++;
  120.                         state++;
  121.                         //向后掠过所有的空白,检测"val的'"'
  122.                         while (line[i] != '\0')
  123.                         {
  124.                             if (line[i] != ' ' && line[i] != '\t')
  125.                             {
  126.                                 if (line[i] != '"')
  127.                                 {
  128.                                     return -1;    //遇到非空白非"字符
  129.                                 }
  130.                                 val_start = ++ i;
  131.                                 break;
  132.                             }
  133.                            
  134.                             ++ i;
  135.                         }
  136.                         if (val_start == -1)
  137.                         {
  138.                             return -1;
  139.                         }
  140.                     }break;
  141.                     default:
  142.                     {
  143.                         //非合法,出错
  144.                         return -1;
  145.                     }break;
  146.                 }
  147.             }break;
  148.             case 3:    //开始解析value
  149.             {
  150.                 switch (line[i])
  151.                 {
  152.                     //val内不应该有非字母字符
  153.                     case '\t':
  154.                     case ' ':
  155.                     case ',':
  156.                     case '\0':
  157.                     case '[':
  158.                     case '}':
  159.                     case ']':
  160.                     case '{':
  161.                     {
  162.                         return -1;
  163.                     }break;
  164.                     case '"':
  165.                     {
  166.                         val_end = i - 1;
  167.                         
  168.                         if (val_end < val_start)
  169.                         {
  170.                             return -1;
  171.                         }
  172.                         ++ i;
  173.                         state++;
  174.                     }break;
  175.                     default:
  176.                     {
  177.                         ++ i;    //正常字母
  178.                     }break;
  179.                 }
  180.             }break;
  181.             case 4:    //最后阶段:如果是line末尾需要检测}]
  182.                     //不是line末尾需要检测',',并且重新进入state = 1
  183.             {
  184.                 // 直接快速的处理过去
  185.                 while (line[i] == ' ' || line[i] == '\t')
  186.                 {
  187.                     ++ i;
  188.                 }
  189.                 if (line[i] == '\0')
  190.                 {
  191.                     return -1; // line末尾,却没有}]
  192.                 }
  193.                 if (line[i] == ',')
  194.                 {
  195.                     // 一个字段结束,打印key,value
  196.                     strncpy(key, line + key_start, key_end - key_start + 1);
  197.                     key[key_end - key_start + 1] = '\0';
  198.                     strncpy(value, line + val_start, val_end - val_start + 1);
  199.                     value[val_end - val_start + 1] = '\0';
  200.                     printf("%s:%s\n", key, value);
  201.                     key_start = key_end = val_start = val_end = -1;
  202.                     
  203.                     // 向后找到value的"
  204.                     while (line[++i] != '\0' && (line[i] == ' ' || line[i] == '\t'));
  205.                     
  206.                     if (line[i] != '"')
  207.                     {
  208.                         return -1;     // , 之后非",错误
  209.                     }
  210.                     key_start = ++ i;
  211.                     state = 1;    //直接进入解析value状态
  212.                 }
  213.                 else if (line[i] == '}')
  214.                 {
  215.                     if (line[i+1] != ']')
  216.                     {
  217.                         return -1;    //}]不完整
  218.                     }
  219.                     
  220.                     strncpy(key, line + key_start, key_end - key_start + 1);
  221.                     key[key_end - key_start + 1] = '\0';
  222.                     strncpy(value, line + val_start, val_end - val_start + 1);
  223.                     value[val_end - val_start + 1] = '\0';
  224.                     printf("%s:%s\n", key, value);
  225.                     return 0;    //解析完毕,}]之后再有字符也不理会了
  226.                 }
  227.                 else
  228.                 {
  229.                     // 意外的字符
  230.                     return -1;
  231.                 }
  232.             }break;
  233.             default:
  234.             {
  235.                 fprintf(stderr, "unknown state %d \n", state);
  236.                 return -1;
  237.             }break;
  238.         }
  239.     }
  240. }
  241. int main()
  242. {
  243.     char test_buffer[1000];
  244.     while (scanf("%s", test_buffer) == 1)
  245.     {
  246.         parse_key_value(test_buffer);
  247.     }
  248.     for (int i = 0; i < 2; ++ i)
  249.     {
  250.         parse_key_value(parse_test[i]);
  251.     }
  252.     return 0;
  253. }
  254. owenliang@linux-7lsl:~/csdn/src> ./main
  255. iconNo:1
  256. seq:1
  257. devStatus:1
  258. devdescribe:asd
  259. iconNo:2
  260. seq:2
  261. devStatus:2
  262. devdescribe:asasdsasdas师大d
复制代码

您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-4-28 02:05 , Processed in 0.013712 second(s), 7 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表