中华人民共和国身份证号码校验码计算方法详解

会有一股神秘感。 提交于 2020-03-02 18:12:13

今天我研究了下身份证号码的校验位,总结如下。

一、身份证号码

根据中华人民共和国国家标准《GB 11643-1999 公民身份号码(Citizen identification number)》,我们的身份证号由18位数字组成,其中前17个数字是本体码(master number),最后一个数字是校验码(check number),校验码是根据本体码的17个数字计算而得的。

(图片摘自《GB 11643-1999》)

在前面17个数字组成的本体码中,最开始的6位是地址码,是由《GB/T 2260 中华人民共和国行政区划代码》规定的,如北京市朝阳区是110105;中间8位数字代表出生日期,前面4位代表年,中间2位代表月,后面2位代表日,如1991年9月20日会被编为19910920;最后3位数字是一个顺序码,顺序码的奇数分配给男性,偶数分配给女性。最后1位是校验码,也就是我们后面要写的内容。

二、如何计算校验码

校验码采用的是国际标准化组织ISO订立的《ISO 7064: 1983》中的“MOD 11-2”校验码系统。

身份证号码一共18位,从右向左被依次编号为1、2、3、4、……、18,现在为各位都设置一个权(weight),用W表示,编号为i的数字权为:W[i]=2^(i-1) (mod 11)

如:W[1]=2^0%11=1;W[2]=2^1%11=2;等等

编号 权重 编号 权重 编号 权重
1 1 7 9 13 4
2 2 8 7 14 8
3 4 9 3 15 5
4 8 10 6 16 10
5 5 11 1 17 9
6 10 12 2 18 7

校验公式为:

其中a[i]代表身份证号上第i位数字,W[i]代表第i位数字的权

因为W[1]的值为1,所以公式又可以写成:

因为a[2]到a[18]即身份证自左向右的前17个数字,是已知的,每一位的权也是已知的,因此可以通过上面这个公式计算出a[1],这个a[1]是身份证号码中最右侧的数字,也就是校验码。

《GB 11643-1999》给出了一个后面大Sigma符号中表达式(下表中用S表示)与校验位a[1]的一一对应关系:

S值 0 1 2 3 4 5 6 7 8 9 10
校验 1 0 X 9 8 7 6 5 4 3 2

因为除法在除数为11时有可能余数为10,10是两位数,因此用罗马数字中代表10的“X”代替。

三、根据本体码计算校验码

以下代码是用C#写的,先添加要用到的命名空间:

using System;
using System.Text.RegularExpressions;

函数:根据本体码计算校验码

/// <summary>
/// 根据本体码计算校验码
/// </summary>
/// <param name="sMasterNumber">本体码(17位)</param>
/// <returns>校验码</returns>
static char CalcCheckNumber(string sMasterNumber)
{
    //本体码必须为17位且全部应为数字
    if (sMasterNumber.Length != 17)
    {
        Console.WriteLine("错误:本体码必须为17位!");
        return ' ';
    }
    if (!Regex.IsMatch(sMasterNumber, @"^\d*$"))
    {
        Console.WriteLine("错误:本体码中所有位都应为数字!");
        return ' ';
    }

    //身份证号码各位的权
    int[] weight = 
    { 
        7, 9, 10, 5, 8, 4, 
        2, 1, 6, 3, 7, 9, 
        10, 5, 8, 4, 2, 1 
    };

    //计算校验位
    int[] id = new int[18];
    for (int i = 0; i < 17; i++)
    {
        id[i] = (int)(sMasterNumber[i] - '0');
    }

    int temp = 0;
    for (int i = 0; i < 17; i++)
    {
        temp += id[i] * weight[i];
    }
    temp = temp % 11;

    switch (temp)
    {
        case 0: return '1';
        case 1: return '0';
        case 2: return 'X';
        case 3: return '9';
        case 4: return '8';
        case 5: return '7';
        case 6: return '6';
        case 7: return '5';
        case 8: return '4';
        case 9: return '3';
        case 10: return '2';
        default: return ' ';
    }
}

下面的Main函数中,给出了两个身份证号码的本体码,分别求出它们完整的身份证号:

static void Main(string[] args)
{
    string sMaster1 = "11010519491231002";
    char cCheck1 = CalcCheckNumber(sMaster1);
    Console.WriteLine("本体码:" + sMaster1);
    Console.WriteLine("校验码:" + cCheck1);
    Console.WriteLine("身份证号码:" + sMaster1 + cCheck1);

    Console.WriteLine("----------");

    string sMaster2 = "44052418800101001";
    char cCheck2 = CalcCheckNumber(sMaster2);
    Console.WriteLine("本体码:" + sMaster2);
    Console.WriteLine("校验码:" + cCheck2);
    Console.WriteLine("身份证号码:" + sMaster2 + cCheck2);

    Console.WriteLine("----------");

    Console.Write("按任意键继续 ...");
    Console.ReadKey(true);
}

运行结果截图:

四、给出身份证号码判断校验码是否正确

在计算机判断身份证号码合理性的时候,有下面几点需要考察:

  • 行政区划代码是否存在?

  • 出生日期是否合理?

  • 校验位数值是否正确?

另外,如果用户还填写过其他信息,比如出生日期、性别等,还可以检查这些项与身份证号码是否一致。

下面这个C#函数,输入一个18位身份证号码,返回校验位数值是否正确:

/// <summary>
/// 判断身份证号校验位是否正确
/// </summary>
/// <param name="IDNumber"></param>
/// <returns></returns>
static bool IsLegalCheckNumber(string sIDNumber)
{
    //身份证号码必须为18位,前17个数字必须为数字,最后一个数字必须为数字或字母X
    if (sIDNumber.Length != 18)
    {
        Console.WriteLine("错误:身份证号码必须为18位!");
        return false;
    }
    if (!Regex.IsMatch(sIDNumber, @"^\d{18}|\d{17}X$"))
    {
        Console.WriteLine(
            "错误:身份证号码前17个数字必须为数字," + 
            "最后一个数字必须为数字或字母X!");
        return false;
    }

    //判断校验位是否合规
    char check = CalcCheckNumber(sIDNumber.Substring(0, 17));
    if (check == sIDNumber[17])
    {
        return true;
    }
    return false;
}

下面的Main函数中,给出了两个身份证号码,分别判断它们的校验位是否正确:

static void Main(string[] args)
{
    string sID1 = "440524188001010014";
    bool bIsLegal1 = IsLegalCheckNumber(sID1);
    Console.WriteLine("身份证号:" + sID1);
    Console.Write("校验结果:");
    Console.WriteLine(bIsLegal1 == true ? "合规" : "不合规");

    Console.WriteLine("----------");

    string sID2 = "44052418800101001X";
    bool bIsLegal2 = IsLegalCheckNumber(sID2);
    Console.WriteLine("身份证号:" + sID2);
    Console.Write("校验结果:");
    Console.WriteLine(bIsLegal2 == true ? "合规" : "不合规");

    Console.WriteLine("----------");

    Console.Write("按任意键继续 ...");
    Console.ReadKey(true);
}

运行结果截图:

END

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!