Excel 身份证号码合法性校验函数说明及其代码逻辑

安装与使用

工具是一个ExcelDNA的 xll 加载项,如下图,32位Excel装前者,64位装后者。

  64位Excel加载如图(还可以配合ExcelDNA的函数参数提示支持xll,这里不做说明)

 

 在【公式】—【函数】可以找到IDCardFuns类下的IDNumCheck函数,用法是=IDNumCheck(身份证号码,性别) 

实现逻辑与代码

身份证号码合法性校验的一般逻辑有:

①位数

18位没得商量;

②性别

一般校验时会有先期录入的性别(“男” or “女”),与通过身份证号码计算出来的性别等于比较;

③出生年月日

a.年龄 是当前计算机系统的年份与身份证年份的差值,大于100判断为错误(这是一个怀疑错误),身份证年份大于系统年份也判断为错误;

b.月份 必须在[1,12]区间内,多了 少了都不对;

c.日期 1.3.5.7.8.10.12这几个31天没得跑,不在[1,31]是不对的,4.6.9.11是[1,30],2月的更复杂了,还得去分平闰年,区间为[1,28]或[1,29]。

④校验码

这个东西应该不多见,但必要。

二代身份证号码的前17位数字是可以通过一个算法,算出第18位的,第18位就叫做校验码。

这个马的逻辑在这儿 

整个代码贴到下面

  public class IDCardFuncs
    {
        [ExcelFunction(Name = "GetGenderFromIDNum", Description = "18位身份证号码提取性别,号码不是18位返回错误提示。", Category = "IDCardFuncs", IsMacroType = true)]
        public static string GetGenderFromIDNum(string idNumber)
        {
            if (idNumber.Length == 18)
            {
                int num;
                if (int.TryParse(idNumber.Substring(16, 1), out num))
                {
                    return (num % 2) switch
                    {
                        1 => "",
                        0 => "",
                        _ => ""
                    };
                }
                else
                { return "身份证号码第16位不是数值"; }
            }
            else
            {
                return "身份证号码不为18位";
            }

        }
        [ExcelFunction(Name = "IDNumCheck", Description = "18位身份证号码合法性检查", Category = "IDCardFuncs", IsMacroType = true)]
        public static string IDNumCheck(string idNum, string gender)
        {
            if (idNum.Length != 18)
                return "身份证号码应为18位";
            else if (!GenderCheck(idNum, gender))
                return "性别与身份证号码不匹配";
            else if (!DateCheck(idNum))
                return "身份证号码出生日期有误";
            else if (CodeCheck(idNum) != idNum.Substring(17, 1).ToUpper())
                return $"校验码不正确,最后一位是{CodeCheck(idNum)}";
            else
                return "True";

        }
        private static bool GenderCheck(string idNum, string gender)
        {
            return IDCardFuncs.GetGenderFromIDNum(idNum) == gender;
        }

        private static bool DateCheck(string idNum)
        {
            bool dateBool = true;
            int year = int.Parse(idNum.Substring(6, 4));
            int month = int.Parse(idNum.Substring(10, 2));
            int date = int.Parse(idNum.Substring(12, 2));

            //年份大于系统时间或者小于当前年份的前100年(大于100岁)判为错
            if (year > System.DateTime.Now.Year || year < System.DateTime.Now.Year - 100 || month < 1 || month > 12) dateBool = false;
            switch (month)
            {
                case 1:
                case 3:
                case 5:
                case 7:
                case 8:
                case 10:
                case 12:
                    if (date == 0 || date > 31)
                        dateBool = false;
                    break;
                case 2:
                    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
                    {
                        if (date == 0 || date > 29)
                            dateBool = false;
                    }
                    else
                    {
                        if (date == 0 || date > 28)
                            dateBool = false;
                    }
                    break;
                default:
                    if (date == 0 || date > 30)
                        dateBool = false;
                    break;
            }
            return dateBool;
        }

        private static string CodeCheck(string idNum)
        {
//变量名懒得想,用了奇葩命名法。
int[] 数字 = new int[idNum.Length]; for (int i = 0; i < idNum.Length - 1; i++) //转身份证号码字符串前17位为int型数组 { 数字[i] = int.Parse(idNum.Substring(i, 1)); } int[] 系数 = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; int 前17位与系数乘积之和 = 0; for (int i = 0; i < 17; i++) { 前17位与系数乘积之和 = 前17位与系数乘积之和 + 数字[i] * 系数[i]; } int 余数 = 前17位与系数乘积之和 % 11; return 余数 switch { 0 => "1", 1 => "0", 2 => "X", 3 => "9", 4 => "8", 5 => "7", 6 => "6", 7 => "5", 8 => "4", 9 => "3", 10 => "2", _ => "" }; } }

 

posted @ 2020-12-01 17:24  yzhyingcool  阅读(2483)  评论(0编辑  收藏  举报