大陆身份证号码格式校验代码

本文介绍了一个用于验证中国身份证号码正确性的C++实现方法。该算法能够处理15位及18位身份证号,并能判断性别。同时,文章还详细解释了如何通过校验码、出生日期等信息来确保身份证号的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • #ifndef __YSP_IDCARD_H__
  • #define __YSP_IDCARD_H__

  • #include <string>
  • #include <stdlib.h>
  • #include <ctype.h>
  • #include <time.h>

  • using namespace std;
  • namespace NS_YSP
  • {
  • // wi =2(n-1)(mod 11)
  • static int32_t wi[18] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 };

  • // verify digit
  • static char vi[11] = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };

  • class IDCard
  • {
  •     public:
  •         //身份证号码校验
  •         static int32_t verify(string idcard, int32_t& gender/*0: 1::表示男*/)
  •         {
  •             //15位身份证升级为18
  •             if ( idcard.length() == 15)
  •             {
  •                 idcard = uptoeighteen(idcard);
  •             }

  •             if (idcard.length() != 18)
  •             {
  •                 return -1;
  •             }

  •             //1-17必须是数字
  •             for(int32_t i = 0; i < 17; ++i)
  •             {
  •                 if( idcard[i] < '0' || idcard[i] > '9')
  •                 {
  •                     return -2;
  •                 }
  •             }
  •             
  •             //最后一位(18)为校验码,检查checksum
  •             char verify = toupper(idcard[17]);
  •             if (verify != checksum(idcard))
  •             {
  •                 return -3;
  •             }
  •             
  •             //1-2位为省级行政区划代码,[11, 65] (第一位华北区1,东北区2,华东区3,中南区4,西南区5,西北区6)
  •             string strProvince = idcard.substr(0, 2);
  •             int32_t nProvince = atoi(strProvince.c_str());
  •             if( nProvince < 11 || nProvince > 65 )
  •             {
  •                 return -4;
  •             }

  •             //3-4为为地级行政区划代码,第5-6位为县级行政区划代码因为经常有调整,这块就不做校验
  •             
  •             //7-10位为出生年份;//11-12位为出生月份 //13-14为出生日期
  •             if( !checkdate(idcard.substr(6,8)) )
  •             {
  •                 return -5;
  •             }

  •             //15-17位为顺序码,表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性
  •             string strSeq = idcard.substr(14,3);
  •             int32_t nSeq = atoi(strSeq.c_str());
  •             gender = nSeq%2;

  •             return 0;
  •         }
  •         
  •         static bool checkdate(const string& strDate)
  •         {
  •             string strYear = strDate.substr(0, 4);
  •             int32_t nYear = atoi(strYear.c_str());

  •             time_t timep;
  •             time(&timep);
  •             struct tm *p = gmtime(&timep);
  •             if( p )
  •             {
  •                 if( nYear < 1900 || nYear > 1900 + p->tm_year )
  •                 {
  •                     return false;
  •                 }

  •                 if( atoi(strDate.c_str()) > ( (1900 + p->tm_year)*10000 + p->tm_mon*100 + p->tm_mday ) )
  •                 {
  •                     return false;
  •                 }
  •             }

  •             string strMon = strDate.substr(4, 2);
  •             int32_t nMon = atoi(strMon.c_str());
  •             if( nMon <= 0 || nMon > 12 )
  •             {
  •                 return false;
  •             }
  •             
  •             //月份天数表
  •             int32_t days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  •             bool bLeapYear = (nYear % 4 == 0 && nYear % 100 != 0) || (nYear % 400 == 0);
  •             if( bLeapYear )
  •             {
  •                 days[1] = 29;
  •             }
  •             string strDay = strDate.substr(6, 2);
  •             int32_t nDay = atoi(strDay.c_str());
  •             if( nDay > days[nMon - 1 ] || nDay <= 0 )
  •             {
  •                 return false;
  •             }

  •             return true;
  •         }

  •         //计算校验码
  •         static char checksum(string eightcardid)
  •         {
  •             int32_t remaining = 0;
  •             int32_t ai[18];

  •             if ( eightcardid.length() == 18 )
  •             {
  •                 eightcardid = eightcardid.substr(0, 17);
  •             }

  •             if ( eightcardid.length() == 17 )
  •             {
  •                 int32_t sum = 0;
  •                 for (int32_t i = 0; i < 17; i++)
  •                 {
  •                     string k = eightcardid.substr(i, 1);
  •                     ai[i] = atoi(k.c_str());
  •                 }

  •                 for (int32_t i = 0; i < 17; i++)
  •                 {
  •                     sum = sum + wi[i] * ai[i];
  •                 }
  •                 remaining = sum % 11;
  •             }
  •             
  •             return vi[remaining];
  •         }

  •         //15位身份证升级到18位身份证号码
  •         static string uptoeighteen(const string& fifteencardid)
  •         {
  •             string eightcardid = fifteencardid.substr(0, 6);
  •             //加上年月日
  •             eightcardid = eightcardid + "19";
  •             eightcardid = eightcardid + fifteencardid.substr(6) ;
  •             //加上校验码
  •             eightcardid.push_back(checksum(eightcardid));
  •             return eightcardid;
  •         }
  • };

  • }

  • #endif
转载 ::饶超勋 stevenrao.blog.chinaunix.net

身份证校验器是一个可以用来验证身份证号码是否有效的验证工具。 特点: 1、支持批量输入验证 2、支持从数据库读取验证 3、支持SQL SERVER 4、支持ORACLE 根据〖中华人民共和国国家标准 GB 11643-1999〗中有关公民身份号码的规定,公民身份号码是由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。 第一、二位表示省(自治区、直辖市、特别行政区)。 第三、四位表示市(地级市、自治州、盟及国家直辖市所属市辖区和县的汇总码)。其中,01-20,51-70表示省直辖市;21-50表示地区(自治州、盟)。 第五、六位表示县(市辖区、县级市、旗)。01-18表示市辖区或地区(自治州、盟)辖县级市;21-80表示县(旗);81-99表示省直辖县级市。 第七、十四位表示出生年月日(单数字月日左侧用0补齐)。其中年份用四位数字表示,年、月、日之间不用分隔符。 第十五、十七位表示顺序码。对同地区、同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。 第十八位表示校验码。作为尾号的校验码,是由号码编制单位按统一的公式计算出来的,校验码如果出现数字10,就用X来代替 中国居民身份证校验码算法: 将身份证号码前面的17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2。 将这17位数字和系数相乘的结果相加。 用加出来和除以11,取余数。 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字。其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2。 通过上面计算得知如果余数是3,第18位的校验码就是9。如果余数是2那么对应的校验码就是X,X实际是罗马数字10。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值