身份证号码校验

/**————**项目开户中身份证校验使用
  1. /***************************************************
  2.  * 功能:验证身份证是否合法 
  3.  * 函 数 名: +(BOOL) chk18PaperId:(NSString *) sPaperId
  4.  * 
  5.  * 函数功能: 校验18位身份证号码 
  6.  * 
  7.  * 输入参数:  sPaperId  身份证号 
  8.  * 
  9.  * 输出参数:                 
  10.  * 
  11.  * 返回值:   0        身份证号码校验成功 
  12.  *           其他     失败
  13. 使用举例:
  14. ************************************************************
  15.  BOOL ret = [NSString chk18PaperId:[_identityCardTF.text uppercaseString]];
           
    if(!ret){
               
    Alert_ARC(@"请输入正确的身份证号",0,nil,nil);
               
    return NO;
  16.           }
  17. ************************************************************

  18. ****************************************************/




+(
BOOL ) chk18PaperId:( NSString *) sPaperId

{
   
// 判断位数
   
if ([sPaperId length ] != 15 && [sPaperId length ] != 18 ) {
       
return NO ;
    }
   
NSString *carid = sPaperId;
   
long lSumQT = 0 ;
   
// 加权因子
   
int R[] ={ 7 , 9 , 10 , 5 , 8 , 4 , 2 , 1 , 6 , 3 , 7 , 9 , 10 , 5 , 8 , 4 , 2 };
   
// 校验码
   
unsigned char sChecker[ 11 ]={ '1' , '0' , 'X' , '9' , '8' , '7' , '6' , '5' , '4' , '3' , '2' };
   
   
   
// 15 位身份证号转换成 18
   
NSMutableString *mString = [ NSMutableString stringWithString :sPaperId];
   
if ([sPaperId length ] == 15 ) {
        [mString
insertString : @"19" atIndex : 6 ];
       
long p = 0 ;
       
const char *pid = [mString UTF8String ];
       
for ( int i= 0 ; i<= 16 ; i++)
        {
            p += (pid[i]-
48 ) * R[i];
        }
       
int o = p% 11 ;
       
NSString *string_content = [ NSString stringWithFormat : @"%c" ,sChecker[o]];
        [mString
insertString :string_content atIndex :[mString length ]];
        carid = mString;
    }
   
   
// 判断地区码
   
NSString * sProvince = [carid substringToIndex : 2 ];
   
if (![ NSString areaCode :sProvince]) {
       
return NO ;
    }
   
   
// 判断年月日是否有效
   
   
// 年份
   
int strYear = [[ NSString getStringWithRange :carid Value1 : 6 Value2 : 4 ] intValue ];
   
// 月份
   
int strMonth = [[ NSString getStringWithRange :carid Value1 : 10 Value2 : 2 ] intValue ];
   
//
   
int strDay = [[ NSString getStringWithRange :carid Value1 : 12 Value2 : 2 ] intValue ];
   
NSTimeZone *localZone = [ NSTimeZone localTimeZone ];
   
NSDateFormatter *dateFormatter = [[[ NSDateFormatter alloc ] init ] autorelease ];
    [dateFormatter
setDateStyle : NSDateFormatterMediumStyle ];
    [dateFormatter
setTimeStyle : NSDateFormatterNoStyle ];
    [dateFormatter
setTimeZone :localZone];
    [dateFormatter
setDateFormat : @"yyyy-MM-dd HH:mm:ss" ];
   
NSDate *date=[dateFormatter dateFromString :[ NSString stringWithFormat : @"%d-%d-%d 12:01:01" ,strYear,strMonth,strDay]];
   
if (date == nil ) {
       
return NO ;
    }
   
const char *PaperId  = [carid UTF8String ];
   
   
// 检验长度
   
if ( 18 != strlen (PaperId)) return - 1 ;
   
   
   
// 校验数字
   
for ( int i= 0 ; i< 18 ; i++)
    {
       
if ( ! isdigit (PaperId[i]) && !(( 'X' == PaperId[i] || 'x' == PaperId[i]) && 17 == i) )
        {
           
return NO ;
        }
    }
   
   
// 验证最末的校验码
   
for ( int i= 0 ; i<= 16 ; i++)
    {
        lSumQT += (PaperId[i]-
48 ) * R[i];
    }
   
if (sChecker[lSumQT% 11 ] != PaperId[ 17 ] )
    {
       
return NO ;
    }
   
return YES ;
}

 

 对于15位的身份证号,先将其扩扩展成18位,再进行校验即可。

 

附身份证编码说明 http://hi.baidu.com/csq9/blog/item/bba84334fdab3d48241f143a.html

------------------------------------------------

 


一、身份证号码执行标准:18位身份证标准在国家质量技术监督局于1999年7月1日实施的GB11643-1999《公民身份号码》。 
  GB11643-1999《公民身份号码》为GB11643-1989《社会保障号码》的修订版,其中指出将原标准名称“社会保障号码”更名为“公民身份号码”,另外GB11643-1999《公民身份号码》从实施之日起代替GB11643-1989。 
二、编码规则:公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位校验码,可以用字母表示如为ABCDEFYYYYMMDDXXXR。其含义如下: 
  1. 地址码(ABCDEF):表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。 
  2. 出生日期码(YYYYMMDD):表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日分别用4位、2位(不足两位加0)、2(同上)位数字表示,之间不用分隔符。 
  3. 顺序码(XXX):表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。 
    4.校验码(R),一位数字,通过前17位数字根据一定计算得出。
三、关于地址码含义的详细解释: 
    身份证前六位是地区代码,我们用ABCDEF表示。 代码的解释规则如下:
    A:国内区域 
      1 华北三省二市 
      2 东北三省 
      3 华东六省一市 
      4 华南六省 
      5 西南四省一市 
      6 西北五省 
      7 台湾 
      8 港澳 
    B(或者说是AB,就是前2位):省(直辖市,自治区,特别行政区)代码 
      按照A划定的分区定义省代码,有直辖市的,直辖市列前,其余按离直辖市的距离排序,没有直辖市的,按离北京的远近排序。 
      具体省(直辖市,自治区,特别行政区)代码如下:
      11-15 京 津冀 晋 蒙 
      21-23 辽 吉黑 
      31-37 沪 苏浙 皖 闽 赣 鲁 
      41-46 豫 鄂湘 粤 桂 琼 
      50-54 渝 川贵 云 藏 
      61-65 陕 甘青 宁 新 
      81-82 港 澳 
    CD:城市代码 
     从01开始排,对于直辖市,CD=01表示市辖区,CD=02表示辖县;省的城市代码从省会开始排,比如2101=沈阳 2102=大连…… 只有地级城市有独立的城市代码,县级市没有。 
    EF:市辖区、郊区、郊县、县级市代码 
    如果EF=00,指代这个城市,不特定区县;对于非直辖市,如EF=01,指代市辖区(任意一个区),02开始指代特定的区。 
          其中: 
          E=0代表市辖区, 
          E=1代表郊区, 
          E=2代表郊县, 
          E=8代表县级市。 
      对于直辖市,从01开始就依次排区,没有市区和郊区的代码区分。
四、生日期码(YYYYMMDD)表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。例如:1981年05月11日就用19810511表示。
五、顺序码(XXX)(身份证第十五位到十七位)是县、区级政府所辖派出所的分配码,每个派出所分配码为10个连续号码,例如“000-009”或“060-069”,其中单数为男性分配码,双数为女性分配码,如遇同年同月同日有两人以上时顺延第二、第三、第四、第五个分配码。如:007的就是个男生,而且和他同年月日生的男生至少有两个,他们的后四位是001*和003*。分配顺序码中“999、998、997、996”四个顺序号分别为男女性百岁以上老人专用的特定编号。
六、关于校验码
校验码是通过一系列数学计算得出来的,具体校验的计算方式如下: 
  1. 对前17位数字本体码加权求和 
  公式为:S = Sum(Ai * Wi), i = 0, ... , 16 
  其中Ai表示第i位置上的身份证号码数字值,Wi表示第i位置上的加权因子,其各位对应的值依次为: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 
    通俗解释:身份证第一位数字X7+第二位X9+第三位X10+第四位X5+第五位X5+第六位X8+第七位X4+第八位X1+第九位X6+第十位X3+十一位X7+十二位X9+十三位X10+十四位X5+十五位X8+十六位X4+十七位X2;计算出总和(用S)表示。
  2. 以11对计算结果取模 
  Y = mod(S, 11) 
    通俗解释:用S除以11,看最后的余数。如果除尽,为0;余数为1,则计为1;最大余数为10;全部数字为0-10共11个数字。(用Y表示)。
  3. 根据模的值得到对应的校验码 
  对应关系为: 
   Y值:   0 1 2 3 4 5 6 7 8 9 10 
  校验码: 1 0 X 9 8 7 6 5 4 3 2 
    通俗解释:余数为0,则校验码为1;依次类推:余数为1,则校验码对应0;以下:2--X;3--9;4--8;5--7;6--6;7--5;8--4;9-3;10-2。
    如果校验码不符合这个规则,则肯定是假号码。
    关于18位身份证号码尾数是“X”的一种解释:因为按照上面的规则,校验码有11个,而不是10个,所以不能用0-9表示。所以如果尾号是10,那么就得用X来代替,因为如果用10做尾号,那么此人的身份证就变成了19位,而19位的号码违反了国家标准,并且我国的计算机应用系统也不承认19位的身份证号码。Ⅹ是罗马数字的10,用X来代替10,可以保证公民的身份证符合国家标准。 
根据〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值