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


        以前浏览网站时,偶尔会发现有些网站注册时需要填写身份证,而且对身份证检验相当严格,猜想必定存在某种算法。今天恰好有空,上网找了一下,有些收获,不敢独享,现与众网友共享。本人已将算法用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

  • 相关阅读:
    Ruby+Appium+testunit实现app自动化demo
    C#+Selenium+Nunit实现Web自动化demo
    Ruby+Selenium+testunit web自动化demo
    Javascript+webdriverio实现app自动化demo
    Java+Appium+Junit实现app自动化demo
    Visual Studio 个人配置和插件
    git 如何处理合并时存在的子模块冲突
    数字货币回测框架准备篇:下载与清洗某安全量历史数据
    扩展期权定价模型到二元期权定价
    package.json
  • 原文地址:https://www.cnblogs.com/wubin264/p/1433731.html
Copyright © 2020-2023  润新知