新旧身份证合法性验证及验证算法

    以前浏览网站时,偶尔会发现有些网站注册时需要填写身份证,而且对身份证检验相当严格,猜想必定存在某种算法。今天恰好有空,上网找了一下,有些收获,不敢独享,现与众网友共享。本人已将算法用C#实现,希望大家能多多指点。

1.         中国公民身份证常识:

我国现行使用公民身份证号码有两种尊循两个国家标准,〖GB 11643-1989〗和〖GB 11643-1999〗。

GB 11643-1989〗中规定的是15位身份证号码:排列顺序从左至右依次为:六位数字地址码,六位数字出生日期码,三位数字顺序码,其中出生日期码不包含世纪数。

6行政区划分代码

6位出生日期

3位顺序

 

       GB 11643-1999〗中规定的是18位身份证号码:公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

6位行政区划分代码

6位出生日期

3位顺序码

1位校验码

       行政区划分代码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码。

       行政区划分代码国家标准GB T 2260-1999

       出生日期码:表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。

       顺序码:表示同一地址码所标识的区域范围内,对同年、同月、同日出生的人员编定的顺序号。顺序码的奇数分给男性,偶数分给女性。

    校验码:是根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2校验码计算出来的检验码。

2.         算法

关于身份证号码最后一位的校验码的算法如下:

假设最后一位的校验码为R

C=(a[i]*w[i])%11 (i=2,3,…,18)

其中∑:表示求和

i:表示身份证号码每一位的序号,从右至左,最左侧为18,最右侧位1

*:表示乘号

a[i]:表示身份证号码第i位上的号码

w[i]:表示第i位上的权值,计算方法:w[i]=2^(i-1)%11

%:表示求模运算

^:表示求幂运算

经过上述方法得到的C的范围在0~10之间,它与身份证最后一位校验位的对应规则为:

C

0

1

2

3

4

5

6

7

8

9

10

R

1

0

X

9

8

7

6

5

4

3

2

由此看出 X 就是 10,罗马数字中的 10 就是X,所以在新标准的身份证号码中可能含有非数字的字母X

3.         C#实现

using System;
using
 System.Collections.Generic;
using
 System.Text;

namespace
 Zwf.IdCard
{
    
public class
 Check
    {
        
//位权值数组

        private static byte[] Weight = new byte[17];
        
//身份证行政区划代码部分长度

        private static byte fPart = 6;
        
//算法求模关键参数

        private static byte fMode = 11;
        
//旧身份证长度

        private static byte oIdLen = 15;
        
//新身份证长度

        private static byte nIdLen = 18;
        
//新身份证年份标记值

        private static string yearFlag = "19";
        
//校验字符串

        private static string checkCode = "10X98765432";
        
//最小行政区划分代码

        private static int minCode = 110000;
        
//最大行政区划分代码

        private static int maxCode = 820000;
        
private static Random rand = new
 Random();

        
/// <summary>

        
/// 计算位权值数组
        
/// </summary>

        private static void SetWBuffer()
        {
            
for (int i = 0; i < Weight.Length; i++
)
            {
                
int k = (int)Math.Pow(2, (Weight.Length -
 i));
                Weight[i] 
= (byte)(k %
 fMode);
            }
        }

        
/// <summary>

        
/// 获取新身份证最后一位校验位
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static string GetCheckCode(string idCard)
        {
            
int sum = 0
;
            
///进行加权求和计算

            for (int i = 0; i < Weight.Length; i++)
            {
                sum 
+= int.Parse(idCard.Substring(i, 1)) *
 Weight[i];
            }
            
///求模运算得到模值

            byte mode = (byte)(sum % fMode);
            
return checkCode.Substring(mode, 1
);
        }

        
/// <summary>

        
/// 检查身份证长度是否合法
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static bool CheckLen(string idCard)
        {
            
if (idCard.Length == oIdLen || idCard.Length ==
 nIdLen)
            {
                
return true
;
            }
            
return false
;
        }

        
/// <summary>

        
/// 验证是否是新身份证
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static bool IsNew(string idCard)
        {
            
if (idCard.Length ==
 nIdLen)
            {
                
return true
;
            }
            
return false
;
        }

        
/// <summary>

        
/// 获取时间串
        
/// </summary>

        
/// <param name="idCard">身份证号码</param>
        
/// <returns></returns>
        private static string GetDate(string idCard)
        {
            
string str = ""
;
            
if
 (IsNew(idCard))
            {
                str 
= idCard.Substring(fPart, 8
);
            }
            
else

            {
                str 
= yearFlag + idCard.Substring(fPart, 6);
            }
            
return
 str;
        }

        
/// <summary>

        
/// 检查时间是否合法
        
/// </summary>

        
/// <param name="idCard"></param>
        
/// <returns></returns>
        private static bool CheckDate(string idCard)
        {
            
//日期是否符合格式

            bool flag = false;
            
string strDate =
 GetDate(idCard);

            
int year = Convert.ToInt32(strDate.Substring(04
));
            
int month = Convert.ToInt32(strDate.Substring(42
));
            
int day = Convert.ToInt32(strDate.Substring(62
));

            
///年份是否合法,本例暂定年份在1900-1999之间为合法年份

            if ((year > 1900&& (year < 2999))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }

            
///检查月份是否合法

            if ((month >= 1&& (month <= 12))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }

            
///检查天是否合法,本例以农历为准

            if ((day >= 1&& (day <= 30))
            {
                flag 
= true
;
            }
            
else

            {
                flag 
= false;
            }
            
return
 flag;
        }

        
/// <summary>

        
/// 根据年份和月份检查天是否合法
        
/// </summary>

        
/// <param name="year">年份</param>
        
/// <param name="month">月份</param>
        
/// <param name="day"></param>
        
/// <returns></returns>
        private static bool CheckDay(int year, int month, int day)
        {
            
///是否是闰年

            bool rYearFlag = false;
            
///天是否合法

            bool rDayFlag = false;
            
if (((year % 4 == 0&& (year % 3200 != 0)) || (year % 400 == 0
))
            {
                rYearFlag 
= true
;
            }

            
#region 检查天是否合法

            
if (month == 2)
            {
                
if
 (rYearFlag)
                {
                    
if (day > 0 && day <= 29
)
                    {
                        rDayFlag 
= true
;
                    }
                }
                
else

                {
                    
if (day > 0 && day <= 28)
                    {
                        rDayFlag 
= true
;
                    }
                }
            }
            
else if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12
)
            {
                
if (day > 0 && day <= 31
)
                {
                    rDayFlag 
= true
;
                }
            }
            
else

            {
                
if (day > 0 && day <= 30)
                {
                    rDayFlag 
= true
;
                }
            }
            
#endregion


            
return rDayFlag;
        }

        
/// <summary>

        
/// 检查身份证是否合法
        
/// </summary>

        
/// <param name="idCard"></param>
        
/// <returns></returns>
        public static bool CheckCard(string idCard, out string msg)
        {
            
///身份证是否合法标志

            bool flag = false;
            msg 
= string
.Empty;
            SetWBuffer();
            
if (!
CheckLen(idCard))
            {
                msg 
= "身份证长度不符合要求"
;
                flag 
= false
;
            }
            
else

            {
                
if (!CheckDate(idCard))
                {
                    msg 
= "身份证日期不符合要求"
;
                    flag 
= false
;
                }
                
else

                {
                    
if (!IsNew(idCard))
                    {
                        idCard 
=
 GetNewIdCard(idCard);
                    }
                    
string checkCode =
 GetCheckCode(idCard);
                    
string lastCode = idCard.Substring(idCard.Length - 11
);
                    
if (checkCode ==
 lastCode)
                    {
                        flag 
= true
;
                    }
                    
else

                    {
                        msg 
= "身份证验证错误";
                        flag 
= false
;
                    }
                }
            }
            
return
 flag;
        }

        
/// <summary>

        
/// 旧身份证号码转换成新身份证号码
        
/// </summary>

        
/// <param name="oldIdCard">旧身份证号码</param>
        
/// <returns>新身份证号码</returns>
        private static string GetNewIdCard(string oldIdCard)
        {
            
if (oldIdCard.Length == 15
)
            {
                
string newIdCard = oldIdCard.Substring(0
, fPart);
                newIdCard 
+=
 yearFlag;
                newIdCard 
+= oldIdCard.Substring(fPart, 9
);
                newIdCard 
+=
 GetCheckCode(newIdCard);
                
return
 newIdCard;
            }
            
return string
.Empty;
        }

        
/// <summary>

        
/// 新身份证号码转换成旧身份证号码
        
/// </summary>

        
/// <param name="newIdCard">新身份证号码</param>
        
/// <returns>旧身份证号码</returns>
        private static string GetOldIdCard(string newIdCard)
        {
            
if (newIdCard.Length == 18
)
            {
                
string oldIdCard = newIdCard.Substring(0
, fPart);
                oldIdCard 
+= newIdCard.Substring(89
);
                
return
 oldIdCard;
            }
            
return string
.Empty;
        }
    }
}

我们可以直接执行方法Zwf.IdCard.Check.CheckCard(身份证号码)进行验证身份证是否正确

该方法返回true表示身份证号码合法,false表示身份证号码不合法。

写得比较粗糙,还望各位高人多指点。

4.         参考资料

"将15位身份证转换为18位身份证":http://www.joyblog.cn/article.asp?id=105

原文地址:https://www.cnblogs.com/wubin264/p/1433731.html