首页 > 编程 > .NET > 正文

用VS.Net编写扩展存储过程(三,完)

2024-07-21 02:07:32
字体:
来源:转载
供稿:网友

昨天忙着写这个,没看奥运会,刚知道老郭和小吴又让外国人郁闷了一把。不知道奥委会是不是又要对跳水改变规则哪?

在上一节,我们把含有两车站的所有火车id和路线信息分别读入了int *trainid和char** ppcstations,完成了最后一次读入数据的过程,下面就要处理这些数据以获得结果……就要结束了,前途是光明的,道路是平坦的……风是背后吹来的……有mm在身边陪着的……晕,忘了告诉各位兄弟,小弟现在不吃西红柿了,改吃鸡蛋,请多多关照积极配合,谢谢~~~

第三步,寻找最短的路线

显然,首先要对路线信息的字符串做分词处理,知道了从一站到下一站需要多长时间,才可能计算最短路线。本文中将用.net类库中提供的正则式类来分割这些字符串……当然用普通方法也完全可以处理。

要使用正则式类,就要用到托管代码,我还是只讲应用,不讲原理。对托管代码工作机制感兴趣的朋友,请参阅msdn中的托管编程部分。

先选择xstrainquery项目的属性,将“配置属性”下“常规”中的“使用托管扩展”改为“是”,随后在proc.cpp中加入如下预编译头:

#using
#using
using namespace system;
using namespace system::text::regularexpressions;
对于char*字符串,必须转化为托展字符串类型,即system::string*指针,才能用正则式类处理。我是用这样的方式把char*转化为system::string*:
system::string *newstr = system::text::encoding::unicode->getstring(system::text::encoding::unicode->getbytes(oldstr));
现在就到了这一步的重头戏——正则式分词。不知道大家有没有掌握.net的正则式,如果象我一样是菜鸟,还是让msdn随时待命吧~
{
    // 把起点和终点站由pbyte转化为system::string*
    system::string *strstart = system::text::encoding::unicode->getstring(system::text::encoding::unicode->getbytes((pchar)pbstart));
    system::string *strend = system::text::encoding::unicode->getstring(system::text::encoding::unicode->getbytes((pchar)pbend));

    // 定义正则式模式
    // 用两个//,是因为|在正则式中有特定含义,必须在|前加上/转义,而//代表了/
    regex *r = new regex(s"( ?://|(.+?),(.+?)小时)+//|");

    // 定义循环中将用到的变量
    int ioldtime = int_max;
    int nfastest = 0;

    // 万事俱备,开始处理ppcstations指针数组
    for (int i=0; i    {
        // 用r来匹配ppcstations[i]
        match *m = r->match(ppcstations[i]);
        // 所有站点的匹配组
        system::text::regularexpressions::group *gstation = m->groups->get_item(1);
        // 所有时间的匹配组,与站点匹配组按顺序一一对应
        system::text::regularexpressions::group *gtime = m->groups->get_item(2);

        // 定义ppcstations[i]所代表的路线所需时间
        int inewtime = 0;
        // 定义是否已经找到起点站的bool变量
        bool bstartfound = false;

        // j从0到gstation中捕获的个数,即总共捕获到多少个站点
        for (int j=0; jcaptures->count; ++j)
        {
            if ( !bstartfound )
            {
                // 如果尚未找到起点,则判断当前捕获站点是否为起点
                if ( gstation->captures->get_item(i)->value->trim()->equals(strstart->trim()) )
                     bstartfound = true;
                // 即使找到了起点,也直接continue,因为起点站对应的时间对运算无意义
                continue;
            }
            else
            {
                 // 已经找到起点站,开始累加路线时间
                 inewtime += int32::parse(gtime->captures->get_item(i)->value->trim());
                 // 看当前捕获站点是否为终点,若是则退出for循环
                 if ( gstation->captures->get_item(i)->value->trim()->equals(strend->trim()) )
                    break;
            }
        }
        // for循环已退出,比较inewtime和ioldtime,并记录较小的路线索引
        if ( inewtime < ioldtime )
        {
             ioldtime = inewtime;
             nfastest = i;
        }
    }
    // 现在,nfastest代表了最短路线的索引,ioldtime则代表所需的最短时间
}

终于找到了最短路线和最短时间,工作完成了!运行运行…………期待…………期待…………焦虑…………疑惑…………不对啊,怎么没有结果?

哦!忘了最后一步,还需要把结果传出……

第四步,也是最后一步,传出结果

结果定义为这样的形式——'车id,需时',生成结果就很简单了:
{
    // 定义一个255字节的数组,较容易处理
    char pcresult[255];
    sprintf(pcresult, "火车id为%d,需时%d小时", pitrainid[nfastest], ioldtime);
}

怎样把pcresult送出去?这就用到了srv.h中定义的srv_paramsetoutput方法,其格式如下:

int srv_paramsetoutput (
srv_proc * srvproc,
int n,
byte * pbdata,
ulong cblen,
bool fnull );

其中,n代表是第几个参数,pbdata代表参数数据,cblen代表参数长度(字节),
若fnull设置为true,则此出参将被强制设为null.

大家肯定注意到,pbdata是一个byte指针,于是我们还要把pcresult转换为byte*,这个很简单,直接显式转换即可。

设置出参的代码如下:
{
     // 得到结果的实际长度(字节数)
     int nresultlen = strlen(pcresult);
     // 传出参数
     srv_paramsetoutput(srvproc, 3, (pbyte)pcresult, nresultlen, false);
 
     // 所有的工作完成后,发出senddone信息
     srv_senddone(psrvproc, (srv_done_count | srv_done_more), 0, 1);
    }

现在工作似乎已经完成了,快拿去运行吧,嘿嘿,多运行几次……再运行几次……陶醉一下……又运行几次……然后……重启计算机,继续往下看。

上面的代码中,我们没有完全释放所分配的资源,所以每次运行都会造成内存泄漏。我们必须在代码的最后加上释放内存空间的语句,比如ppcstations, pitrainid等。

大功告成,第一个问题得到了解决。

本来还想写第二个问题的,可第二个问题和第一个问题的区别只在于第三步,即如何计算最短路线的算法上,这个,我相信我现在用的方法一定不是最好的,就不拿出来献丑了。

原来写篇文章是这么累的……


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表