试用EF开发WEB应用程序(6): 解析Query String中的各参数值

67 篇文章 1 订阅
23 篇文章 0 订阅

题记:用“易语言.飞扬”(EF)开发WEB应用程序,此前还没有先例。但因为EF本地开发包(EFNDK)已经发布,用C/C++开发一个EF类库,使其支持EF开发WEB应用程序,应该并非难事。当然也可想而知,其中必有诸多难点有待解决。此系列文章,为本人探索过程之记录,对外人未必有多大价值。如有网友乐观其事,还请理性待之。 作者:liigo。转载请务必注明出处:http://blog.csdn.net/liigo/在线留言


试用EF开发WEB应用程序(6): 解析Query String中的各参数值 

 

之前的文章提到,Query String的主要形式是 name1=value1&name2=value2&...,即由 & 符号分隔的多个“名称=值”文本(有时“值”为空,其形式为“名称=”)。在 CGI / FastCGI 程序(以及 JSP/ASP/PHP/PERL等)中,对QueryString进行文本处理,解析出其各“名称”“值”,以便根据“名称”获取对应的值,是非常普遍的操作。这甚至可以理解的 CGI / FastCGI 程序的核心动作,——没有此动作,大部分程序将无法工作。在EF类库 fastcgi.efn 中,我内置了QueryString解析功能。

QueryString是很规则的文本,处理起来不难,主要应该考虑执行效率。在解析之前,有两个准备工作:1、从环境变量QUERY_STRING中读取QueryString文本;2、对上一步得到的QueryString进行URL解码。然后,正常的解析工作就开始了。下面列出EF类库 fastcgi.efn 中解析 QueryString 的C++代码:

void  _FCGIClass_ParseQueryString_IfNeed(FCGIClass_FieldsData *  pFields)
{
    
if (pFields -> hasParsedQueryString)  return ;
    pFields->hasParsedQueryString = EF_TRUE;

    _FCGIClass_Read_QUERY_STRING_IfNeed(pFields);

    EFChar
*  szQueryString  =  EF_GET_TEXT(pFields -> queryString);
    
if (szQueryString[ 0 ==  myC( ' /0 ' ))
    {
        EF_DEC_REF_COUNT(pFields
-> queryStringNames); pFields -> queryStringNames  =  EF_EMPTY_ARRAY;
        EF_DEC_REF_COUNT(pFields
-> queryStringValues); pFields -> queryStringValues  =  EF_EMPTY_ARRAY;
        
return ;
    }

    EF_MiniMem names, values;
    names.AddInt(
0 ); names.AddInt( 1 ); names.AddInt( 0 );
    values.AddInt(
0 ); values.AddInt( 1 ); values.AddInt( 0 );

    EFChar
*  ps  =  szQueryString;
    EFChar
*  psFrom  =  szQueryString;
    
int  count  =   0 ;
    bool inName 
=   true ;

    
for (; ; ps ++ )
    {
        
if ( * ps  ==  myC( ' = ' ))
        {
            names.AddInt((EFInt)_NewEFText(psFrom, ps 
-  psFrom));
            psFrom 
=  ps  +   1 ;
            count
++ ;
            inName 
=   false ;
        }
        
else   if ( * ps  ==  myC( ' & ' ))
        {
            
if (inName)  // key1&...
            {
                names.AddInt((EFInt)_NewEFText(psFrom, ps 
-  psFrom));
                values.AddInt((EFInt)EF_EMPTY_TEXT);
                psFrom 
=  ps  +   1 ;
                count
++ ;
                
continue ;
            }

            values.AddInt((EFInt)_NewEFText(psFrom, ps 
-  psFrom));
            psFrom 
=  ps  +   1 ;
            inName 
=   true ;
        }
        
else   if ( * ps  ==  myC( ' /0 ' ))
        {
            
if ( * (ps - 1 ==  myC( ' & ' ))  // key1=value1&
                 break ;

            
if (inName)  // key1
            {
                names.AddInt((EFInt)_NewEFText(psFrom, ps 
-  psFrom));
                values.AddInt((EFInt)EF_EMPTY_TEXT);
                count
++ ;
            }
            
else
                values.AddInt((EFInt)_NewEFText(psFrom, ps 
-  psFrom));
            
            
break ;
        }
    }

    names.ReplaceInt(
2   *  sizeof(EFDWord), count);
    values.ReplaceInt(
2   *  sizeof(EFDWord), count);

    EFArray nameArray 
=  EF_GC_REG_TEXT_ARRAY_DATA(names.Detach());
    EFArray valueArray 
=  EF_GC_REG_TEXT_ARRAY_DATA(values.Detach());
    EF_DEC_REF_COUNT(pFields
-> queryStringNames); pFields -> queryStringNames  =  nameArray;
    EF_DEC_REF_COUNT(pFields
-> queryStringValues); pFields -> queryStringValues  =  valueArray;

    
// cache to hashmap
    EFText *  pNames   =  (EFText * ) ((EFByte * )nameArray  +   3   *  sizeof(EFDWord));
    EFText
*  pValues  =  (EFText * ) ((EFByte * )valueArray  +   3   *  sizeof(EFDWord));
    
for ( int  i  =  count  -   1 ; i  >=   0 ; i -- )
    {
        pFields
-> queryStringNameValueHashmap -> Set(EF_GET_TEXT(pNames[i]), pValues[i]);
    }
}

代码应该是比较清晰的。首先是处理缓存,如果之前已经解析过一次,直接使用上次解析结果;如果曾经读取(包括进行URL解码)过QueryString,直接使用已经读取并解码后的值,不进行重复工作。接下来是文本解析,得到“名称”数组,及与其对应的“值”数组,这两个数组的成员是一一对应的。最后,依然是缓存,将各“名称”“值”配对放入一个哈希表中,以便此后可以根据“名称”高速查询得到“值”。在EF程序中,当 fcgi.QUERY_STRING(name) 被调用时,除了第一次调用时需进行解析工作外,后续调用则直接从哈希表中查询得到结果,执行效率应该是非常高的。(今后我可能会实际测试一下结果,研究它对程序执行效率的提升究竟有多么明显。) 在上面的C++代码中,对一些非正常的、不合法的QueryString,也有适当的容错处理。

如果代码有错误或疏忽、遗漏之处,请各位批评指正。

注意:本文给出的代码在处理顺序上存在错误,需先分隔再解码,而不应该先解码再分隔!用围棋上的术语说是“次序错了”。这个是必须更正的,有时间我马上处理。 

 

下文预告:“简单计算器”实例程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值