头歌Python作业——8.1 模拟生成身份信息及查验身份(project)

目录

第1关 

第2关 

第3关 

第4关 


第1关 

import random
def person_name(gender_of_id, last_name_file, male_name_file, female_name_file):
    """
    @参数 gender_of_id:性别,字符串类型
    @参数 last_name_file:百家姓文件名,字符串类型
    @参数 male_name_file:男性常用名文件名,字符串类型
    @参数 female_name_file:女性常用名文件名,字符串类型
    接收性别、百家姓文件名、男性常用名文件名、女性常用名文件名为参数
    先随机抽取一个姓氏,再根据性别随机抽取名字,
    返回表示姓名的字符串。
    """
    with open(last_name_file, 'r', encoding='utf-8') as data:
        last = [line.strip().replace(',', '').replace('。', '')
                for line in data]
    last1 = ''.join(last[:51])
    last2 = ''.join(last[51:])
    last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)]  # 得到姓的列表
    last_name = random.choice(last)                                                 # 随机一个姓
    with open(male_name_file, 'r', encoding='utf-8') as data:
        male_name = data.readline().split()
    with open(female_name_file, 'r', encoding='utf-8') as data:
        female_name = data.readline().split()
    if gender_of_id == '男':
        first_name = random.choice(male_name)
    else:
        first_name = random.choice(female_name)
    return last_name + first_name
def judge(txt):
    """接收一个字符串为参数.
    如果参数值为“性别”,输出当前模拟身证上的性别;
    如果参数值为“姓名”,输出当前模拟身证上的姓名。
    """
    if txt == '姓名':
        print(person)
    elif txt == '性别':
        print(user_gender)
    else:
        print('输入错误')
if __name__ == '__main__':
    last_name_filename = 'data/family names.txt'    # 百家姓
    male_name_filename = 'data/popularNameM.txt'    # 男性名来源文件
    female_name_filename = 'data/popularNameF.txt'  # 女性名来源文件
    random.seed(int(input()))                       # 随机数种子,不用于自动评测时注释掉此行
    user_gender = random.choice('男女')               # 随机生成男或女
    person = person_name(user_gender, last_name_filename, male_name_filename, female_name_filename)  # 根据性别生成人名
    text = input()
    judge(text)


第2关 

import random
import datetime
def person_name(gender_of_id, last_name_file, male_name_file, female_name_file):
    """
    @参数 gender_of_id:性别,字符串类型
    @参数 last_name_file:百家姓文件名,字符串类型
    @参数 male_name_file:男性常用名文件名,字符串类型
    @参数 female_name_file:女性常用名文件名,字符串类型
    接收性别、百家姓文件名、男性常用名文件名、女性常用名文件名为参数
    先随机抽取一个姓氏,再根据性别随机抽取名字,
    返回表示姓名的字符串。
    """
    with open(last_name_file, 'r', encoding='utf-8') as data:
        last = [line.strip().replace(',', '').replace('。', '')
                for line in data]
    last1 = ''.join(last[:51])
    last2 = ''.join(last[51:])
    last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)]  # 得到姓的列表
    last_name = random.choice(last)                                                 # 随机一个姓
    with open(male_name_file, 'r', encoding='utf-8') as data:
        male_name = data.readline().split()
    with open(female_name_file, 'r', encoding='utf-8') as data:
        female_name = data.readline().split()
    if gender_of_id == '男':
        first_name = random.choice(male_name)
    else:
        first_name = random.choice(female_name)
    return last_name + first_name
def area_code(area_file):
    """
    @参数 area_file:包含地区编码的文件名,字符串类型
    传入参数为包含地区编码和地区名的文件名的字符串,以地区编码为键,地区名为值构建字典作为返回值。
    """
    area_of_birth = {}
    with open(area_file, 'r', encoding='utf-8') as data:
        for x in data:
            ls = x.strip().split(',')
            area_of_birth[ls[0]] = ls[1]        # 得到保存地区编码的字典
    return area_of_birth
def birthdate():
    """在1900-2020间随机抽取一个数字作为出生年份,再随机生成一个合法的包含月和日的日期。需
    要注意月份范围为1-12,1、3、5、7、8、10、12月的日期范围为1-31,4、6、9、11的日期范围为1-30,闰年2月
    的日期范围为1-29,平年2月的日期范围为1-28。年为4位字符串,月和日均为2位字符串,依序构成长
    度为8的字符串作为返回值,例如19840509 """
    year_of_birth = random.choice(range(1900, 2020))
    days_of_rand = datetime.timedelta(days=random.randint(1, 366))
    date_of_birth = datetime.datetime.strptime(str(year_of_birth)+'0101', "%Y%m%d") + days_of_rand          # 月份和日期项
    return date_of_birth.strftime("%Y%m%d")  # 19840509
def order_number(gender_of_id):
    """接收表示性别的字符串为参数,随机抽取1-99之间的整数作为生出顺序号,根据传入的性别随
    机抽取第17位序号数字,男性为偶数,女性为奇数。"""
    num = random.choice(range(1, 100))
    # gender_num = random.choice('13579') if gender_of_id == '男' else random.choice('02468')
    if gender_of_id == '男':
        gender_num = random.choice('13579')
    else:
        gender_num = random.choice('02468')
    return '{:02}'.format(num) + str(gender_num)
def id_of_17(area_of_code, birth_date, birth_order):
    """
    @参数 area_of_code:字符串
    @参数 birth_date:字符串
    @参数 birth_order:字符串
    接收地区码字典,出生日期和出生顺序号,随机抽取一个地区码,返回身份证号前17位的字符串。
    需要注意的是,抽取地区码时,要避免抽取到省或地级市的编码(最后2位编码为0)。
    """
    area_no_city = [x for x in area_of_code.keys() if x[-2:] != '00']
    area_id = random.choice(area_no_city)  # 避免抽到省市的编码
    return area_id + birth_date + birth_order
def id17_to_18(id_number):
    """
    @ 参数 id_number:身份证号前17位,字符串
    为身份证号增加校验位,接收身份证号码前17位,返回18位身份证号,校验码的计算方法为:
    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,其中的X是罗马数字10;
    5. 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ;如果余数是10,
       身份证的最后一位号码就是2。
    """
    ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    s = sum([int(id_number[i]) * ls[i] for i in range(17)])      # 将数字与该位上的权值相乘放入列表并求和
    id_number = id_number + ecc[s % 11]                          # 以位权和对11取余为索引获得校验位上的字符
    return id_number                                             # 函数返回值为18位的身份证号
def village_of_live(village_file, area_of_code):
    """
    @ 参数 village_file:包含常见小区名的文件名,字符串类型
    @ 参数 area_of_code:地区编码,字典类型
    从village_file中随机选择一个小区名,从area_of_code中随机选择一个地区编码,并从中获取省、市、
    县(区)名。楼栋号限制[1-30]中随机,单元号限制[1-7]中随机,楼层号限制[1-35]中随机,
    房间号限制[1-4]中随机。
    """
    with open(village_file, 'r', encoding='utf-8') as data:
        village_live = data.readline().split()
    village = random.choice(village_live)
    building = random.choice(range(1, 30))
    door = random.choice(range(1, 7))
    floor = random.choice(range(1, 35))
    room = random.choice(range(1, 4))
    area_id = random.choice([x for x in list(area_of_code.keys()) if x[-2:] != '00'])  # 避免抽到省市的编码
    province = area_of_code.get(area_id[:2]+'0000', '')
    city = area_of_code.get(area_id[:4]+'00', '')
    area = area_of_code[area_id]
    if area_id[:2] in ['11', '12', '31', '50']:          # 北京市,上海市,天津市,重庆市
        address_of_live = f'{province}{area}'
    else:
        address_of_live = f'{province}{city}{area}'
    address_of_live = address_of_live + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
    return address_of_live, area_id
def all_of_nation(nation_file):
    """
    @参数 nation_file:文件名,字符串类型
    传入参数为包含民族的文件名,从中随机抽取一个民族为返回值。
    需要注意的是,返回值里不包含'族'字,例如抽取'蒙古族',返回值为'蒙古'。
    """
    with open(nation_file, 'r', encoding='utf-8') as data:
        nation_name = data.readline().split()
    nation = random.choice(nation_name)
    return nation[:-1]
def judge(txt):
    """接收一个字符串为参数。
    如果参数值为“住址”,输出当前模拟身证上的住址;
    如果参数值为“身份证”,按身份证格式输出当前模拟身证上的全部信息;
    """
    if txt == '身份证号':
        print(id18)
    elif txt == '住址':
        print(address_and_code[0])
    else:
        print('输入错误')
if __name__ == '__main__':
    last_name_filename = 'data/family names.txt'  # 百家姓
    male_name_filename = 'data/popularNameM.txt'  # 男性名来源文件
    female_name_filename = 'data/popularNameF.txt'  # 女性名来源文件
    area_filename = 'data/IDcode.txt'  # 地区码
    village_filename = 'data/villageName.txt'  # 常用小区名
    nation_filename = 'data/nation.txt'  # 民族
    random.seed(int(input()))  # 随机数种子,不用于自动评测时注释掉此行
    user_gender = random.choice('男女')  # 随机生成男或女
    person = person_name(user_gender, last_name_filename, male_name_filename, female_name_filename)  # 根据性别生成人名
    area_number = area_code(area_filename)  # 地区编码,字典类型
    date = birthdate()  # 随机生日
    order = order_number(user_gender)  # 随机出生序号
    id17 = id_of_17(area_number, date, order)  # 拼接身份证号前17位
    id18 = id17_to_18(id17)  # 加校验码成18位身份证号
    address_and_code = village_of_live(village_filename, area_number)
    nationality = all_of_nation(nation_filename)
    text = input()
    judge(text) 


第3关 

import random
import datetime
def person_name(gender_of_id, last_name_file, male_name_file, female_name_file):
    """
    @参数 gender_of_id:性别,字符串类型
    @参数 last_name_file:百家姓文件名,字符串类型
    @参数 male_name_file:男性常用名文件名,字符串类型
    @参数 female_name_file:女性常用名文件名,字符串类型
    接收性别、百家姓文件名、男性常用名文件名、女性常用名文件名为参数
    先随机抽取一个姓氏,再根据性别随机抽取名字,
    返回表示姓名的字符串。
    """
    with open(last_name_file, 'r', encoding='utf-8') as data:
        last = [line.strip().replace(',', '').replace('。', '')
                for line in data]
    last1 = ''.join(last[:51])
    last2 = ''.join(last[51:])
    last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)]  # 得到姓的列表
    last_name = random.choice(last)                                                 # 随机一个姓
    with open(male_name_file, 'r', encoding='utf-8') as data:
        male_name = data.readline().split()
    with open(female_name_file, 'r', encoding='utf-8') as data:
        female_name = data.readline().split()
    if gender_of_id == '男':
        first_name = random.choice(male_name)
    else:
        first_name = random.choice(female_name)
    return last_name + first_name
def area_code(area_file):
    """
    @参数 area_file:包含地区编码的文件名,字符串类型
    传入参数为包含地区编码和地区名的文件名的字符串,以地区编码为键,地区名为值构建字典作为返回值。
    """
    area_of_birth = {}
    with open(area_file, 'r', encoding='utf-8') as data:
        for x in data:
            ls = x.strip().split(',')
            area_of_birth[ls[0]] = ls[1]        # 得到保存地区编码的字典
    return area_of_birth
def birthdate():
    """在1900-2020间随机抽取一个数字作为出生年份,再随机生成一个合法的包含月和日的日期。需
    要注意月份范围为1-12,1、3、5、7、8、10、12月的日期范围为1-31,4、6、9、11的日期范围为1-30,闰年2月
    的日期范围为1-29,平年2月的日期范围为1-28。年为4位字符串,月和日均为2位字符串,依序构成长
    度为8的字符串作为返回值,例如19840509 """
    year_of_birth = random.choice(range(1900, 2020))
    days_of_rand = datetime.timedelta(days=random.randint(1, 366))
    date_of_birth = datetime.datetime.strptime(str(year_of_birth)+'0101', "%Y%m%d") + days_of_rand          # 月份和日期项
    return date_of_birth.strftime("%Y%m%d")  # 19840509
def order_number(gender_of_id):
    """接收表示性别的字符串为参数,随机抽取1-99之间的整数作为生出顺序号,根据传入的性别随
    机抽取第17位序号数字,男性为偶数,女性为奇数。"""
    num = random.choice(range(1, 100))
    # gender_num = random.choice('13579') if gender_of_id == '男' else random.choice('02468')
    if gender_of_id == '男':
        gender_num = random.choice('13579')
    else:
        gender_num = random.choice('02468')
    return '{:02}'.format(num) + str(gender_num)
def id_of_17(area_of_code, birth_date, birth_order):
    """
    @参数 area_of_code:字符串
    @参数 birth_date:字符串
    @参数 birth_order:字符串
    接收地区码字典,出生日期和出生顺序号,随机抽取一个地区码,返回身份证号前17位的字符串。
    需要注意的是,抽取地区码时,要避免抽取到省或地级市的编码(最后2位编码为0)。
    """
    area_no_city = [x for x in area_of_code.keys() if x[-2:] != '00']
    area_id = random.choice(area_no_city)  # 避免抽到省市的编码
    return area_id + birth_date + birth_order
def id17_to_18(id_number):
    """
    @ 参数 id_number:身份证号前17位,字符串
    为身份证号增加校验位,接收身份证号码前17位,返回18位身份证号,校验码的计算方法为:
    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,其中的X是罗马数字10;
    5. 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ;如果余数是10,
       身份证的最后一位号码就是2。
    """
    ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    s = sum([int(id_number[i]) * ls[i] for i in range(17)])      # 将数字与该位上的权值相乘放入列表并求和
    id_number = id_number + ecc[s % 11]                          # 以位权和对11取余为索引获得校验位上的字符
    return id_number                                             # 函数返回值为18位的身份证号
def village_of_live(village_file, area_of_code):
    """
    @ 参数 village_file:包含常见小区名的文件名,字符串类型
    @ 参数 area_of_code:地区编码,字典类型
    从village_file中随机选择一个小区名,从area_of_code中随机选择一个地区编码,并从中获取省、市、
    县(区)名。楼栋号限制[1-30]中随机,单元号限制[1-7]中随机,楼层号限制[1-35]中随机,
    房间号限制[1-4]中随机。
    """
    with open(village_file, 'r', encoding='utf-8') as data:
        village_live = data.readline().split()
    village = random.choice(village_live)
    building = random.choice(range(1, 30))
    door = random.choice(range(1, 7))
    floor = random.choice(range(1, 35))
    room = random.choice(range(1, 4))
    area_id = random.choice([x for x in list(area_of_code.keys()) if x[-2:] != '00'])  # 避免抽到省市的编码
    province = area_of_code.get(area_id[:2]+'0000', '')
    city = area_of_code.get(area_id[:4]+'00', '')
    area = area_of_code[area_id]
    if area_id[:2] in ['11', '12', '31', '50']:          # 北京市,上海市,天津市,重庆市
        address_of_live = f'{province}{area}'
    else:
        address_of_live = f'{province}{city}{area}'
    address_of_live = address_of_live + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
    return address_of_live, area_id
def all_of_nation(nation_file):
    """
    @参数 nation_file:文件名,字符串类型
    传入参数为包含民族的文件名,从中随机抽取一个民族为返回值。
    需要注意的是,返回值里不包含'族'字,例如抽取'蒙古族',返回值为'蒙古'。
    """
    with open(nation_file, 'r', encoding='utf-8') as data:
        nation_name = data.readline().split()
    nation = random.choice(nation_name)
    return nation[:-1]
def print_id(full_name, gender_of_id, id_number, address, nation, birth_date):
    """
    @ 参数 full_name:姓名,字符串类型
    @ 参数 gender_of_id: 性别,字符串类型
    @ 参数 id_number:公民身份证号, 字符串类型
    @ 参数 address:住址, 字符串类型
    @ 参数 nation:民族, 字符串类型
    @ 参数 birth_date:出生年月日, 字符串类型
    按身份证正面的格式输出完整的身份信息,包括:
    姓名
    性别   民族
    出生年月日
    住址
    公民身份证号"""
    print('-------------------------------------------------')
    print()
    print(f'  姓  名  {full_name}')
    print(f'  性  别  {gender_of_id}   民族  {nation}')
    print(f'  出  生  {birth_date[:4]} 年 {int(birth_date[4:6])} 月 {int(birth_date[6:])} 日')
    print(f'  住  址  {address[0]}')
    print()
    print(f'  公民身份证号码 {id_number}')
    print('-------------------------------------------------')
def area_of_live(area_id, area_of_code):
    """
    @参数 area_id:居住地编码,字符串
    @参数 area_of_code:地区编码,字典
    接收居住地编码和地区编码字典为参数,返回持证人居住地址的省市县(区)
    需要注意的是,若持证人居住地为直辖市,则住址中无地级市,直接输出市和区,例如:北京市朝阳区
    其他地区格式例如:湖北省武汉市洪山区。
    """
    province = area_of_code[area_id[:2] + '0000']  # 根据字典的键获得其值,省份
    if area_id[:2] in ['11', '12', '31', '50']:    # 北京市,上海市,天津市,重庆市
        district = area_of_code[area_id]  # 根据字典的键获得其值,县区
        return f'持证人居住于{province}{district}'
    else:
        city = area_of_code[area_id[:4] + '00']  # 根据字典的键获得其值,市区
        district = area_of_code[area_id]  # 根据字典的键获得其值,县区
        return f'持证人居住于{province}{city}{district}'
# 查验城市的编码
def check_city_code(city_name, area_of_code):
    """接收一个表示城市名的字符串参数和地区编码,若城市名存在,返回值为该城市对应的地区编码,6位字符串。
    若城市名不存在,返回False。
    @参数 city_name:城市名,字符串
    @参数 area_of_code:地区编码,字典类型
    """
    for code, v in area_of_code.items():
        if v == city_name:
            return code
    else:
        return False
def check_city(id_number, city_name, city_code, area_live):
    """
    @ 参数 id_number:身份证号,字符串类型
    @ 参数 city_name:查验城市名,字符串类型
    @ 参数 city_code:城市编码,字符串类型
    @ 参数 area_live:居住地信息,字符串类型
    接收参数身份证号,查验城市名和城市编码,居住地信息,查验持证人是否与指定的城市相关
    若居住地与查验城市名相同,返回持证人居住于city_name市
    否则若出生地与查验城市相同,返回持证人出生于city_name市
    其他情况返回持证人与city_name无关联。
    """
    if city_name in area_live:
        return f'持证人居住于{city_name}'
    elif city_code[:4] == id_number[:4]:
        return f'持证人出生于{city_name}'
    else:
        return f'持证人与{city_name}无关联'
def judge(txt):
    """接收一个字符串为参数。
    如果参数值为“身份证”,按身份证格式输出当前模拟身证上的全部信息;
    如果参数值为“查询”,,要求用户输入一个要查询的人名,再输入一个单词做为匹配词,
    根据输入设置敏感地区,判定持证人是否为敏感地区常住人或是敏感地区出生者。。"""
    if txt == '身份证':
        print_id(person, user_gender, id18, address_and_code, nationality, date)
    elif txt == '查询':
        city_name = input()  # 输入敏感城市名
        city_code = check_city_code(city_name, area_number)
        if city_code:
            print(check_city(id18, city_name, city_code, address_and_code[0]))
        else:
            print('城市输入错误,请输入包含"市"在内的城市名')
        print(area_of_live(address_and_code[1], area_number))
    else:
        print('输入错误')
if __name__ == '__main__':
    last_name_filename = 'data/family names.txt'    # 百家姓
    male_name_filename = 'data/popularNameM.txt'    # 男性名来源文件
    female_name_filename = 'data/popularNameF.txt'  # 女性名来源文件
    area_filename = 'data/IDcode.txt'               # 地区码
    village_filename = 'data/villageName.txt'       # 常用小区名
    nation_filename = 'data/nation.txt'             # 民族
    random.seed(int(input()))                       # 随机数种子,不用于自动评测时注释掉此行
    user_gender = random.choice('男女')               # 随机生成男或女
    person = person_name(user_gender, last_name_filename, male_name_filename, female_name_filename)  # 根据性别生成人名
    area_number = area_code(area_filename)       # 地区编码,字典类型
    date = birthdate()                           # 随机生日
    order = order_number(user_gender)                 # 随机出生序号
    id17 = id_of_17(area_number, date, order)    # 拼接身份证号前17位
    id18 = id17_to_18(id17)                      # 加校验码成18位身份证号
    address_and_code = village_of_live(village_filename, area_number)
    nationality = all_of_nation(nation_filename)
    text = input()
    judge(text) 


第4关 

import random
import datetime
def person_name(gender_of_id, last_name_file, male_name_file, female_name_file):
    """
    @参数 gender_of_id:性别,字符串类型
    @参数 last_name_file:百家姓文件名,字符串类型
    @参数 male_name_file:男性常用名文件名,字符串类型
    @参数 female_name_file:女性常用名文件名,字符串类型
    接收性别、百家姓文件名、男性常用名文件名、女性常用名文件名为参数
    先随机抽取一个姓氏,再根据性别随机抽取名字,
    返回表示姓名的字符串。
    """
    with open(last_name_file, 'r', encoding='utf-8') as data:
        last = [line.strip().replace(',', '').replace('。', '')
                for line in data]
    last1 = ''.join(last[:51])
    last2 = ''.join(last[51:])
    last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)]  # 得到姓的列表
    last_name = random.choice(last)                                                 # 随机一个姓
    with open(male_name_file, 'r', encoding='utf-8') as data:
        male_name = data.readline().split()
    with open(female_name_file, 'r', encoding='utf-8') as data:
        female_name = data.readline().split()
    if gender_of_id == '男':
        first_name = random.choice(male_name)
    else:
        first_name = random.choice(female_name)
    return last_name + first_name
def area_code(area_file):
    """
    @参数 area_file:包含地区编码的文件名,字符串类型
    传入参数为包含地区编码和地区名的文件名的字符串,以地区编码为键,地区名为值构建字典作为返回值。
    """
    area_of_birth = {}
    with open(area_file, 'r', encoding='utf-8') as data:
        for x in data:
            ls = x.strip().split(',')
            area_of_birth[ls[0]] = ls[1]        # 得到保存地区编码的字典
    return area_of_birth
def birthdate():
    """在1900-2020间随机抽取一个数字作为出生年份,再随机生成一个合法的包含月和日的日期。需
    要注意月份范围为1-12,1、3、5、7、8、10、12月的日期范围为1-31,4、6、9、11的日期范围为1-30,闰年2月
    的日期范围为1-29,平年2月的日期范围为1-28。年为4位字符串,月和日均为2位字符串,依序构成长
    度为8的字符串作为返回值,例如19840509 """
    year_of_birth = random.choice(range(1900, 2020))
    days_of_rand = datetime.timedelta(days=random.randint(1, 366))
    date_of_birth = datetime.datetime.strptime(str(year_of_birth)+'0101', "%Y%m%d") + days_of_rand          # 月份和日期项
    return date_of_birth.strftime("%Y%m%d")  # 19840509
def order_number(gender_of_id):
    """接收表示性别的字符串为参数,随机抽取1-99之间的整数作为生出顺序号,根据传入的性别随
    机抽取第17位序号数字,男性为偶数,女性为奇数。"""
    num = random.choice(range(1, 100))
    # gender_num = random.choice('13579') if gender_of_id == '男' else random.choice('02468')
    if gender_of_id == '男':
        gender_num = random.choice('13579')
    else:
        gender_num = random.choice('02468')
    return '{:02}'.format(num) + str(gender_num)
def id_of_17(area_of_code, birth_date, birth_order):
    """
    @参数 area_of_code:字符串
    @参数 birth_date:字符串
    @参数 birth_order:字符串
    接收地区码字典,出生日期和出生顺序号,随机抽取一个地区码,返回身份证号前17位的字符串。
    需要注意的是,抽取地区码时,要避免抽取到省或地级市的编码(最后2位编码为0)。
    """
    area_no_city = [x for x in area_of_code.keys() if x[-2:] != '00']
    area_id = random.choice(area_no_city)  # 避免抽到省市的编码
    return area_id + birth_date + birth_order
def id17_to_18(id_number):
    """
    @ 参数 id_number:身份证号前17位,字符串
    为身份证号增加校验位,接收身份证号码前17位,返回18位身份证号,校验码的计算方法为:
    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,其中的X是罗马数字10;
    5. 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ;如果余数是10,
       身份证的最后一位号码就是2。
    """
    ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    s = sum([int(id_number[i]) * ls[i] for i in range(17)])      # 将数字与该位上的权值相乘放入列表并求和
    id_number = id_number + ecc[s % 11]                          # 以位权和对11取余为索引获得校验位上的字符
    return id_number                                             # 函数返回值为18位的身份证号
def village_of_live(village_file, area_of_code):
    """
    @ 参数 village_file:包含常见小区名的文件名,字符串类型
    @ 参数 area_of_code:地区编码,字典类型
    从village_file中随机选择一个小区名,从area_of_code中随机选择一个地区编码,并从中获取省、市、
    县(区)名。楼栋号限制[1-30]中随机,单元号限制[1-7]中随机,楼层号限制[1-35]中随机,
    房间号限制[1-4]中随机。
    """
    with open(village_file, 'r', encoding='utf-8') as data:
        village_live = data.readline().split()
    village = random.choice(village_live)
    building = random.choice(range(1, 30))
    door = random.choice(range(1, 7))
    floor = random.choice(range(1, 35))
    room = random.choice(range(1, 4))
    area_id = random.choice([x for x in list(area_of_code.keys()) if x[-2:] != '00'])  # 避免抽到省市的编码
    province = area_of_code.get(area_id[:2]+'0000', '')
    city = area_of_code.get(area_id[:4]+'00', '')
    area = area_of_code[area_id]
    if area_id[:2] in ['11', '12', '31', '50']:          # 北京市,上海市,天津市,重庆市
        address_of_live = f'{province}{area}'
    else:
        address_of_live = f'{province}{city}{area}'
    address_of_live = address_of_live + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
    return address_of_live, area_id
def all_of_nation(nation_file):
    """
    @参数 nation_file:文件名,字符串类型
    传入参数为包含民族的文件名,从中随机抽取一个民族为返回值。
    需要注意的是,返回值里不包含'族'字,例如抽取'蒙古族',返回值为'蒙古'。
    """
    with open(nation_file, 'r', encoding='utf-8') as data:
        nation_name = data.readline().split()
    nation = random.choice(nation_name)
    return nation[:-1]
def print_id(full_name, gender_of_id, id_number, address, nation, birth_date):
    """
    @ 参数 full_name:姓名,字符串类型
    @ 参数 gender_of_id: 性别,字符串类型
    @ 参数 id_number:公民身份证号, 字符串类型
    @ 参数 address:住址, 字符串类型
    @ 参数 nation:民族, 字符串类型
    @ 参数 birth_date:出生年月日, 字符串类型
    按身份证正面的格式输出完整的身份信息,包括:
    姓名
    性别   民族
    出生年月日
    住址
    公民身份证号"""
    print('-------------------------------------------------')
    print()
    print(f'  姓  名  {full_name}')
    print(f'  性  别  {gender_of_id}   民族  {nation}')
    print(f'  出  生  {birth_date[:4]} 年 {int(birth_date[4:6])} 月 {int(birth_date[6:])} 日')
    print(f'  住  址  {address[0]}')
    print()
    print(f'  公民身份证号码 {id_number}')
    print('-------------------------------------------------')
# 获取和输出身份证注册地的省、市、县(区)
def area_of_registration(id_number, area_of_code):
    """
    @参数 id_number:身份证号,字符串
    @参数 area_of_code:地区编码,字典
    接收身份证号和地区编码的字典为参数,返回持证人身份证注册地址的省市县(区)。
    省的编码末4位为0
    地级市(区)编码末2位为0
    需要注意的是,若持证人注册地为直辖市,则住址中无地级市,直接输出市和区,例如:北京市朝阳区
    其他地区格式例如:湖北省武汉市洪山区。
    """
    code = id_number[:6]
    province = area_of_code[code[:2] + '0000']
    city = area_of_code[code[:4] + '00']
    district = area_of_code[code]
    if code[:2] in ['11', '12', '31', '50']:          # 北京市,上海市,天津市,重庆市
        return f'持证人出生于{province}{district}'
    else:
        return f'持证人出生于{province}{city}{district}'
def area_of_live(area_id, area_of_code):
    """
    @参数 area_id:居住地编码,字符串
    @参数 area_of_code:地区编码,字典
    接收居住地编码和地区编码字典为参数,返回持证人居住地址的省市县(区)
    需要注意的是,若持证人居住地为直辖市,则住址中无地级市,直接输出市和区,例如:北京市朝阳区
    其他地区格式例如:湖北省武汉市洪山区。
    """
    province = area_of_code[area_id[:2] + '0000']  # 根据字典的键获得其值,省份
    if area_id[:2] in ['11', '12', '31', '50']:    # 北京市,上海市,天津市,重庆市
        district = area_of_code[area_id]  # 根据字典的键获得其值,县区
        return f'持证人居住于{province}{district}'
    else:
        city = area_of_code[area_id[:4] + '00']  # 根据字典的键获得其值,市区
        district = area_of_code[area_id]  # 根据字典的键获得其值,县区
        return f'持证人居住于{province}{city}{district}'
# 查验城市的编码
def check_city_code(city_name, area_of_code):
    """接收一个表示城市名的字符串参数和地区编码,若城市名存在,返回值为该城市对应的地区编码,6位字符串。
    若城市名不存在,返回False。
    @参数 city_name:城市名,字符串
    @参数 area_of_code:地区编码,字典类型
    """
    for code, v in area_of_code.items():
        if v == city_name:
            return code
    else:
        return False
def check_city(id_number, city_name, city_code, area_live):
    """
    @ 参数 id_number:身份证号,字符串类型
    @ 参数 city_name:查验城市名,字符串类型
    @ 参数 city_code:城市编码,字符串类型
    @ 参数 area_live:居住地信息,字符串类型
    接收参数身份证号,查验城市名和城市编码,居住地信息,查验持证人是否与指定的城市相关
    若居住地与查验城市名相同,返回持证人居住于city_name市
    否则若出生地与查验城市相同,返回持证人出生于city_name市
    其他情况返回持证人与city_name无关联。
    """
    if city_name in area_live:
        return f'持证人居住于{city_name}'
    elif city_code[:4] == id_number[:4]:
        return f'持证人出生于{city_name}'
    else:
        return f'持证人与{city_name}无关联'
def age_of_id(id_number):
    """接收身份证号为参数,返回值为持证人年龄和性别。
    年龄的计算方式为当前年份减出生年份。
    @参数 id_number:身份证号,字符串类型。
    """
    current_year = datetime.datetime.now().year
    gender = '男' if id_number[16] in '13579' else '女'
    age = current_year - int(id_number[6:10])
    return gender, age
def judge(txt):
    """接收一个字符串为参数,如果参数值为“姓名”,输出当前模拟身证上的姓名;
    如果参数是身份证号,输出当前模拟的身份证号的号码。如果参数值是“住址”,输出当前身份证号上的住址。
    如果参数值为“性别”,输出当前模拟身证上的性别;
    如果参数值为“姓名”,输出当前模拟身证上的姓名;
    如果参数值为“住址”,输出当前模拟身证上的住址;
    如果参数值为“身份证”,按身份证格式输出当前模拟身证上的全部信息;
    如果参数值为“查询”,,要求用户输入一个要查询的人名,再输入一个单词做为匹配词,
    根据输入设置敏感地区,判定持证人是否为敏感地区常住人或是敏感地区出生者。。"""
    if txt == '姓名':
        print(person)
    elif txt == '性别':
        print(user_gender)
    elif txt == '身份证号':
        print(id18)
    elif txt == '住址':
        print(address_and_code[0])
    elif txt == '身份证':
        print_id(person, user_gender, id18, address_and_code, nationality, date)
    elif txt == '查询':
        city_name = input()  # 输入敏感城市名
        city_code = check_city_code(city_name, area_number)
        if city_code:
            print(check_city(id18, city_name, city_code, address_and_code[0]))
        else:
            print('城市输入错误,请输入包含"市"在内的城市名')
        print(area_of_live(address_and_code[1], area_number))
    else:
        print('输入错误')
if __name__ == '__main__':
    last_name_filename = 'data/family names.txt'    # 百家姓
    male_name_filename = 'data/popularNameM.txt'    # 男性名来源文件
    female_name_filename = 'data/popularNameF.txt'  # 女性名来源文件
    area_filename = 'data/IDcode.txt'               # 地区码
    village_filename = 'data/villageName.txt'       # 常用小区名
    nation_filename = 'data/nation.txt'             # 民族
    random.seed(int(input()))                       # 随机数种子,不用于自动评测时注释掉此行
    user_gender = random.choice('男女')               # 随机生成男或女
    person = person_name(user_gender, last_name_filename, male_name_filename, female_name_filename)  # 根据性别生成人名
    area_number = area_code(area_filename)       # 地区编码,字典类型
    date = birthdate()                           # 随机生日
    order = order_number(user_gender)                 # 随机出生序号
    id17 = id_of_17(area_number, date, order)    # 拼接身份证号前17位
    id18 = id17_to_18(id17)                      # 加校验码成18位身份证号
    address_and_code = village_of_live(village_filename, area_number)
    nationality = all_of_nation(nation_filename)
    text = input()
    judge(text)

如果此文章对你有所帮助,麻烦点个赞,谢谢~~~

点赞加关注,追新不迷路~~~

  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

萌新发文啦~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值