身份证验证算法(C++实现)

来源:互联网 发布:管家婆软件试用 编辑:程序博客网 时间:2024/05/16 06:21

#include <iostream>
#include <string>
using namespace std;

//作者:sbfqmq E-Mail:sbfqmqyhaha@163.com

/*

公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成.排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。
1、地址码
表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按 GB/T 2260 的规定执行。 

2、出生日期码

表示编码对象出生的年、月、日,按 GB/T 7408 的规定执行。年、月、日代码之间不用分隔符。
例:某人出生日期为 1966年10月26日,其出生日期码为 19661026。
3、顺序码
表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数千分配给女性。
4 、校验码
校验码采用ISO 7064:1983,MOD 11-2 校验码系统。
(1)十七位数字本体码加权求和公式 S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和 Ai:表示第i位置上的身份证号码数字值 Wi:表示第i位置上的加权因子 Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
(2)计算模 Y = mod(S, 11)
(3)通过模得到对应的校验码 : 0 1 2 3 4 5 6 7 8 9 10 
                    校验码: 1 0 X 9 8 7 6 5 4 3 2

*/
int IsRight(string card);
 bool BirthdayIsRight(string cardId);
int GetDay(int year,int month);
int main(int argc,char ** argv)
{
 string card_id,sex,year,month,day;
 while(1)
 {
 cin>>card_id;
 int flag=IsRight(card_id);
 cout<<flag<<endl;
 }
 getchar();
 return 0;
}
int IsRight(string card)
{
    int error=0;
 int length=(int)card.length();
 cout<<length<<endl;
 int index=card.find_first_not_of("1234567890");
 if(index!=card.npos)
 {
   error=-1;  //号码中有非数字字符
 }
    if(!BirthdayIsRight(card))
 {
     error=-4; //出生年月错误
 }
 if(length==18)     //验证18位身份证号码
 {
 int no[]={7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
 char id[]={'1','0','X','9','8','7','6','5','4','3','2'};
                        //1 0 X 9 8 7 6 5 4 3 2   校验码
    const char *p=card.c_str();
 int i=0,wi=0,sum=0;
 for(;i<length-1;i++)
 {
  wi=(*(p+i)-'0')*no[i];
  sum+=wi;
 }
 if(*(p+i)<'0'||*(p+i)>'9')
 {
   if (*(p+i)!='X'&&*(p+i)!='x')
   {
     error=-2;//身份证最后一位输入错误
   }
 }
 wi=sum%11;
  if(*(p+17)=='x'||*(p+17)=='X')            //最后一位为'x'或'X';
             {
                if(id[wi]!='x'&&id[wi]!='X')
                    error=-3;
             }
        else if(id[wi]!=*(p+17))     //判断计算出的身份证校验码与输入是否相符
  {
   error=-3;
      }
 }
 return error;

}
 //判断身份证号码中的年月日是否正确
  bool BirthdayIsRight(string cardId)
  {
    string year,month,day;
    bool flag=false;
 int length=cardId.length();
   if(length==18){
    year=cardId.substr(6,4);//取18位身份证中的年
    month=cardId.substr(10,2); // 月
    day=cardId.substr(12,2);   //日
    }
    else
    {
    year=cardId.substr(6,2);//取15位身份证中的年
    month=cardId.substr(8,2); // 月
    day=cardId.substr(10,2);   //日
    year="19"+year;
    }
    if(atoi(year.c_str())==0||atoi(month.c_str())==0||atoi(day.c_str())==0)
 {
  flag=false;
 }
 else if(GetDay(atoi(year.c_str()),atoi(month.c_str()))>=atoi(day.c_str()))
    {
     flag=true;
    }
    return flag;
  }

//得到指定年跟月的天数
int GetDay(int year,int month)
  {
      int day=0;
       switch (month)
       {
       case 1:
       case 3:
       case 5:
       case 7:
       case 8:
       case 10:
       case 12:
       {
        day=31;
       break;
       }
       case 4:
       case 6:
       case 9:
       case 11:
       {
       day=30;
       break;
       }
        case 2:
        {
        if(year%4==0&&year%100!=0||year%400==0)
        day=29;
        else
        day=28;
          break;
        }
        default :  {
         day=-1;
        break;
        }
       }

       return day;
  }