sscanf函数与字段长度

软件世界

  初看题目,朋友们可能觉得很奇怪,sscanf函数与数据库字段长度好像风马牛不相及嘛。其实不然,从下面的例子中你会看出,它们不仅很有关系,而且不注意的话有可能酿成大错。

  功能需求

  在数据库中定义“个人资料表”,用于存放个人信息,其中身份证字段(person_idno)为字符型,18位长度。服务程序从数据通讯区得到客户端上传的身份证号码,然后与数据库中早先注册的身份证号码比较,以便确定该身份证是否已注册,如果身份证已注册,将为客户提供相应的服务,否则提示“客户证件不符”,拒绝服务。

  一般实现方法

  其实这是个很常见的问题,一般的实现方法用伪程序代码表述如下。

  sscanf(comm._area,"%18s",id_no)

  exec select person_idno into :ID_NO

  from 个人资料表

  where 惟一确定一条记录

  if(strcmp(id_no,ID_NO)!=0)

  {提示“证件不符”}

  Else{为客户提供服务}

  分析

  表面看来,这段程序毫无纰漏,但在实际运行过程中你会发现,明明是正确的身份证号码,系统也会提示“证件不符”。为什么呢?让我们仔细分析一下。

  1.对sscanf理解不足

  一般地,我们在通讯区中都使用定长格式,即使输入15位证件号码,在通讯时也会用空格补足18位,那么,你会认为使用sscanf(comm._area,"%18s",id_no)语句,肯定可以得到18位的证件号码。其实不然,阅读sscanf的帮助信息可以知道,sscanf可以读取各种基本类型的数据并自动把它转换为指定的“格式”,当有多个数据项时,必须用空白符(空格、制表符、换行、进纸)来分隔开。

  本例中,在输入流中出现空格符将引起对当前变量赋值操作的终止。即上传15位字符串加3位空格符构成的18位身份证号码,通过上述函数只能得到15位长度的id_no。你可以通过strlen(id_no)来验证。同样地,对于通讯区是“123456789 7654321”的情况,因为中间有两位空格,sscanf(comm._area,"%18s",id_no)只能得到9位长度的字符串。

  2.对字段长度概念不清

  对于一般定长字符类型的字段,其长度是一定的。就像上例中定义的身份证(person_id no),定义为18位,那么它肯定就是18位,即便只输入了15位或更少。在SYBASE中采用char_length函数可以看到字段的长度。

  改进

  明白了以上两个基本概念,我们就可以采取以下两种方法来改进上面的算法。

  1.补足位数

  以数据库中的字段长度为准,对服务程序进行改进,上传的身份证号码如果不足18位,立即补足:

  strncat(id_no," ",18-strlen(id_no))  

  提示:语句中间有18个空格。如果id_no已经是18位长度,则18-strlen(id_no)为0,不对id_no修正,否则根据id_no长度,在id_no后增加0~18个空格,将id_no补足为18位。

  2.改造SQL语句

  以服务程序得到的身份证长度为准改造select语句,利用rtrim函数截掉person_idno字段后的空格:

  exec select (rtrim(per son_idno)) into :ID_NO

  from 个人资料表

  where 惟一确定一条记录