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

最近项目用到身份证校验,在提交公安系统做实名校验前,需要自己检查一下身份证格式是否正确;毕竟每查询一次需要money啊;
提前排除用户随手输入的号码。因此贴出了分享一下
  1. #ifndef __YSP_IDCARD_H__
  2. #define __YSP_IDCARD_H__

  3. #include <string>
  4. #include <stdlib.h>
  5. #include <ctype.h>
  6. #include <time.h>

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

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

  14. class IDCard
  15. {
  16.     public:
  17.         //身份证号码校验
  18.         static int32_t verify(string idcard, int32_t& gender/*0: 女 1::表示男*/)
  19.         {
  20.             //把15位身份证升级为18位
  21.             if ( idcard.length() == 15)
  22.             {
  23.                 idcard = uptoeighteen(idcard);
  24.             }

  25.             if (idcard.length() != 18)
  26.             {
  27.                 return -1;
  28.             }

  29.             //1-17必须是数字
  30.             for(int32_t i = 0; i < 17; ++i)
  31.             {
  32.                 if( idcard[i] < '0' || idcard[i] > '9')
  33.                 {
  34.                     return -2;
  35.                 }
  36.             }
  37.             
  38.             //最后一位(第18位)为校验码,检查checksum值
  39.             char verify = toupper(idcard[17]);
  40.             if (verify != checksum(idcard))
  41.             {
  42.                 return -3;
  43.             }
  44.             
  45.             //第1-2位为省级行政区划代码,[11, 65] (第一位华北区1,东北区2,华东区3,中南区4,西南区5,西北区6)
  46.             string strProvince = idcard.substr(0, 2);
  47.             int32_t nProvince = atoi(strProvince.c_str());
  48.             if( nProvince < 11 || nProvince > 65 )
  49.             {
  50.                 return -4;
  51.             }

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

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

  63.             return 0;
  64.         }
  65.         
  66.         static bool checkdate(const string& strDate)
  67.         {
  68.             string strYear = strDate.substr(0, 4);
  69.             int32_t nYear = atoi(strYear.c_str());

  70.             time_t timep;
  71.             time(&timep);
  72.             struct tm *p = gmtime(&timep);
  73.             if( p )
  74.             {
  75.                 if( nYear < 1900 || nYear > 1900 + p->tm_year )
  76.                 {
  77.                     return false;
  78.                 }

  79.                 if( atoi(strDate.c_str()) > ( (1900 + p->tm_year)*10000 + p->tm_mon*100 + p->tm_mday ) )
  80.                 {
  81.                     return false;
  82.                 }
  83.             }

  84.             string strMon = strDate.substr(4, 2);
  85.             int32_t nMon = atoi(strMon.c_str());
  86.             if( nMon <= 0 || nMon > 12 )
  87.             {
  88.                 return false;
  89.             }
  90.             
  91.             //月份天数表
  92.             int32_t days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  93.             bool bLeapYear = (nYear % 4 == 0 && nYear % 100 != 0) || (nYear % 400 == 0);
  94.             if( bLeapYear )
  95.             {
  96.                 days[1] = 29;
  97.             }
  98.             string strDay = strDate.substr(6, 2);
  99.             int32_t nDay = atoi(strDay.c_str());
  100.             if( nDay > days[nMon - 1 ] || nDay <= 0 )
  101.             {
  102.                 return false;
  103.             }

  104.             return true;
  105.         }

  106.         //计算校验码
  107.         static char checksum(string eightcardid)
  108.         {
  109.             int32_t remaining = 0;
  110.             int32_t ai[18];

  111.             if ( eightcardid.length() == 18 )
  112.             {
  113.                 eightcardid = eightcardid.substr(0, 17);
  114.             }

  115.             if ( eightcardid.length() == 17 )
  116.             {
  117.                 int32_t sum = 0;
  118.                 for (int32_t i = 0; i < 17; i++)
  119.                 {
  120.                     string k = eightcardid.substr(i, 1);
  121.                     ai[i] = atoi(k.c_str());
  122.                 }

  123.                 for (int32_t i = 0; i < 17; i++)
  124.                 {
  125.                     sum = sum + wi[i] * ai[i];
  126.                 }
  127.                 remaining = sum % 11;
  128.             }
  129.             
  130.             return vi[remaining];
  131.         }

  132.         //把15位身份证升级到18位身份证号码
  133.         static string uptoeighteen(const string& fifteencardid)
  134.         {
  135.             string eightcardid = fifteencardid.substr(0, 6);
  136.             //加上年月日
  137.             eightcardid = eightcardid + "19";
  138.             eightcardid = eightcardid + fifteencardid.substr(6) ;
  139.             //加上校验码
  140.             eightcardid.push_back(checksum(eightcardid));
  141.             return eightcardid;
  142.         }
  143. };

  144. }

  145. #endif

你可能感兴趣的:(大陆身份证号码格式校验代码)