身份证的秘密(高级)——PTA

文章详细解释了身份证号码的结构、组成以及校验规则,包括地址码、出生日期码、顺序码和校验码的含义,并提供了校验算法实例。
摘要由CSDN通过智能技术生成

/*特别鸣谢——猫猫学姐*/

小明特别想知道自己身份证号码的秘密,那我就告诉你吧!

公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位校验码,可以用字母表示为:

ABCDEFYYYYMMDDXXXR。

1.地址码ABCDEF。表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260标准的规定执行。
2.出生日期码YYYYMMDD。表示编码对象出生的年、月、日,按GB/T7408标准的规定执行,年、月、日代码之间不用分隔符。
3.顺序码XXX。表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。
4.校验码R。根据前面十七位数字码,按照ISO 7064:1983.MOD 11-2标准校验码计算出来的检验码。

18位身份证号码的编排规则: 
(1)前1、2位数字表示:所在省份的代码; 
11:"北京",12:"天津",13:"河北",14:"山西",15:"内蒙古"
21:"辽宁",22:"吉林",23:"黑龙江"
31:"上海",32:"江苏",33:"浙江",34:"安徽",35:"福建",36:"江西",37:"山东"
41:"河南",42:"湖北",43:"湖南",44:"广东",45:"广西",46:"海南"
50:"重庆",51:"四川",52:"贵州",53:"云南",54:"西藏"
61:"陕西",62:"甘肃",63:"青海",64:"宁夏",65:"新疆"
81:"香港",82:"澳门",83:"台湾地区
91:"国外"
(2)第3、4位数字表示:所在城市的代码; 
(3)第5、6位数字表示:所在区县的代码; 
(4)第7~14位数字表示:出生年、月、日; 
(5)第15、16位数字表示:所在地的派出所的代码; 
(6)第17位数字表示性别:奇数表示男性,偶数表示女性; 
(7)第18位数字是校检码:是由计算产生的,用来检验身份证的正确性。校检码可以是0~9的数字,有时也用x表示。

第十八位数字的计算方法为: 
(1)将前面的身份证号码17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:
7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2
(2)将这17位数字和系数相乘的结果相加。
(3)用加出来和除以11,看余数是多少?
(4)余数只可能有0  1  2   3  4  5  6  7  8  9 10 这11个数字。其分别对应的最后一位
身份证的号码为1  0  X   9  8  7  6  5  4  3  2。
(5)通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。 

例如:某男性的身份证号码是34052419800101001X。我们要看看这个身份证是不是合法的身份证。 
首先:我们得出,前17位数字与相应系数的乘积和是189。
然后:用189除以11得出的结果是17余2,也就是说余数是2。
最后:通过对应规则就可以知道余数2对应的数字是x。所以,这是一个合格的身份证号码。

现在,于老师给你一个身份证号,你能知道它是不是一个合法的号码?如果是合法的你知道这个号码是男是女吗?

输入格式:

一行中一串号码,最多18位,可能不是18位,每位也可能不是数字或X,没空格。

输出格式:
请按如下顺序判断并输出结果
1.不够18位,直接输出(X为实际读到的位数):
No WeiShuBuZu:X
以下情况需要首先一行原样输出身份证号,如果其中有非法字符用括号括上。
2.有非法字符,即前17位不是数字或第18位不是数字和X,先输出号码本身(非法字符用括号括上),再输出(X为非法字符个数):
No FeiFaZiFu:X
3.省份代码不合法,输出(XX为出错的省份码):
No ShengFenDaiMa:XX
4.出生日期不是合法日期,输出(YYYYMMDD为出错的日期):
No ChuShengRiQi:YYYYMMDD
5.第18位校验代码错误,输出(E为错误代码R为计算得到的正确代码):
No JiaoYanHaoMa:E(R is right)
(不合法的号码只需要按以上顺序输出第一个原因)。
合法号码根据性别输出:Yes male(男)或者Yes female(女)
输入样例1:
34052419800101001
输出样例1:
No WeiShuBuZu:17
输入样例2:
3$0524198:010100Rx
输出样例2:
3($)0524198(:)010100(R)x
No FeiFaZiFu:3
输入样例3:
25042120021715082x
输出样例3:
25042120021715082x
No ShengFenDaiMa:25
输入样例4:
23042120021715082x
输出样例4:
23042120021715082x
No ChuShengRiQi:20021715
输入样例5:
340524198001010017
输出样例5:
340524198001010017
No JiaoYanHaoMa:7(X is right)
输入样例6:
34052419800101001X
输出样例6:
34052419800101001X
Yes male
#include <stdio.h>
#include <string.h>

int count = 0;
char jym;
char s[19];

int ch(char s[]) //字符,前17位不是数字或18位不是数字/x
{
    char b[19] = {0}; //b为哈希表,记录非法位置
    for (int i = 0; i < 18; i++) //判断并记录是否合法
    {
        if (s[i] < '0' || s[i] > '9')
        {
            if (i == 17 && (s[i] == 'x' || s[i] == 'X'))
                continue;
            b[i] = 1;
            count++;
        }
    }
    if (count != 0)
    {
        for (int i = 0; i < 18; i++)
        {
            if (b[i] == 1)
            {
                printf("(%c)", s[i]);
            }
            else
                printf("%c", s[i]);
        }
        printf("\n");
        return 1;
    }
    return 0;
}

int province(char s[]) //省份
{
    int pro[10][10] = {{0}, {0, 1, 1, 1, 1, 1}, {0, 1, 1, 1}, {0, 1, 1, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, {0}, {0, 1, 1, 1}, {0, 1}};
    //二维数组哈希表储存合法省份代码,第一位为行第二位为列,合法置1
    if (pro[(int)(s[0] - '0')][(int)(s[1] - '0')] != 1)
        return 1;
    return 0;
}

int birth(char s[]) //生日
{
    int mon[15] = {0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //数组储存每个月日期,二月单独算
    int y, m, d;
    y = 1000 * (s[6] - '0') + 100 * (s[7] - '0') + 10 * (s[8] - '0') + (s[9] - '0');
    m = 10 * (s[10] - '0') + (s[11] - '0');
    d = 10 * (s[12] - '0') + (s[13] - '0');
    if (m < 1 || m > 12)
        return 1;
    if (m == 2)
    {
        if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
            mon[2] = 29;
        else
            mon[2] = 28;
    }
    if (d < 1 || d > mon[m])
        return 1;
    return 0;
}

int ISO(char s[]) //校验码
{
    int xi[20] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    char yu[15] = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    //哈希表预处理系数和余数
    int sum = 0, remainder;
    for (int i = 0; i < 17; i++)
        sum += xi[i] * (s[i] - '0');
    remainder = sum % 11;
    jym = yu[remainder];
    if (s[17] != jym)
    {
        if (jym == 'X' && s[17] == 'x')
            return 0;
        return 1;
    }
    return 0;
}

int main()
{
    scanf("%s", s);
    if (strlen(s) < 18)
    {
        printf("No WeiShuBuZu:%lu\n", strlen(s));
    }
    else if (ch(s) == 1)
    {
        printf("No FeiFaZiFu:%d\n", count);
    }
    else if (province(s) == 1)
    {

        printf("No ShengFenDaiMa:%c%c\n", s[0], s[1]);
    }
    else if (birth(s) == 1)
    {

        printf("No ChuShengRiQi:");
        for (int i = 6; i < 14; i++)
            printf("%c", s[i]);
        printf("\n");
    }
    else if (ISO(s) == 1)
    {

        printf("No JiaoYanHaoMa:%c(%c is right)\n", s[17], jym);
    }
    else
    {

        if ((s[16] - '0') % 2 == 0)
            printf("Yes female\n");
        else
            printf("Yes male\n");
    }
    return 0;
}

身份证号码中包含了很多的信息,可以通过身份证号码得到以下信息: 1. 姓名:身份证号码中的第一个字符到第十七个字符表示身份证持有人的姓名,其中最后一位可能是数字或者字母X,表示身份证号码的校验位。 2. 出生日期:身份证号码中的第七个字符到第十四个字符表示身份证持有人的出生日期,格式为年月日。 3. 性别:身份证号码中的第十五个字符表示身份证持有人的性别,奇数表示男性,偶数表示女性。 4. 地址码:身份证号码中的第十七个字符到第十八个字符表示身份证持有人所在的行政区划代码。 5. 校验码:身份证号码中的最后一位是校验码,用于检验身份证号码的有效性。 在Python中,可以通过正则表达式和字符串切片等方式提取身份证号码中的各个信息。例如: ```python import re id_card = '110101199003076677' # 提取姓名 name = id_card[0:6] print('姓名:', name) # 提取出生日期 birthday = id_card[6:14] print('出生日期:', birthday) # 提取性别 gender = int(id_card[16]) if gender % 2 == 0: print('性别:女') else: print('性别:男') # 提取地址码 address_code = id_card[17:19] print('地址码:', address_code) # 校验身份证号码的有效性 pattern = re.compile(r'^\d{17}[\dX]$') if not pattern.match(id_card): print('身份证号码格式错误!') else: # 计算校验码 factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] check_code = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] sum = 0 for i in range(17): sum += int(id_card[i]) * factor[i] if check_code[sum % 11] == id_card[17]: print('身份证号码有效!') else: print('身份证号码无效!') ``` 以上代码演示了如何从身份证号码中提取姓名、出生日期、性别和地址码,并校验身份证号码的有效性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值