模拟生成 一 个身份证信息

    1. 模拟姓名,从百家姓中抽取一个姓,从常用名中抽取一个名字
    2. 模拟出生日期
    3. 性别随机男或女
    4. 民族从56个民族中随机取一个
    5. 模拟居住地址,地,省、市、县区随机,随机一个小区、30以内整数楼号、楼层号35以内,房间号取01,02,03。地址格式为四川甘孜白玉县土博士城12栋2单元2601室
    6. 模拟生成18位身份证号,出生序号1-99内随机取
    7. 疫情期间检查身份证号,需从身份证号码和住址两种验证是否来自湖北或武汉

    准备工作,需要准备和整理百家姓、男和女性的常用名、身份证地区与地区码、常用小区名、民族等文件。为方便维护,数据文件统一放在当前路径下的data文件夹下:

    1. lastNameFile = './data/百家姓.txt' # 姓取自百家姓
    2. firstNameFileM = './data/popularNameM.txt' # 男性名来源文件
    3. firstNameFileF = './data/popularNameF.txt' # 女性名来源文件
    4. areaFile = './data/IDcode.txt'
    5. villageFile = './data/villageName.txt'
    6. nationFile = './data/nation.txt'

    先随机性别和姓,再根据性别随机生成一个名字:

    1. import random
    2. def personName(gender,lastNameFile,firstNameFileM,firstNameFileF): # 根据性别生成一个姓名
    3. with open(lastNameFile, 'r', encoding='utf-8') as data:
    4. last = [line.strip().replace(',', '').replace('。', '') for line in data]
    5. last1 = ''.join(last[:51])
    6. last2 = ''.join(last[51:])
    7. last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)] # 得到姓的列表
    8. lastname = random.choice(last) # 随机一个姓
    9. with open(firstNameFileM, 'r', encoding='utf-8') as data:
    10. MaleName = data.readline().split()
    11. with open(firstNameFileF, 'r', encoding='utf-8') as data:
    12. FemaleName = data.readline().split()
    13. firstName = random.choice(MaleName) if gender == '男' else random.choice(FemaleName)
    14. return lastname + firstName
    15. if __name__ == '__main__':
    16. lastNameFile = './data/百家姓.txt' # 姓取自百家姓
    17. firstNameFileM = './data/popularNameM.txt' # 男性名来源文件
    18. firstNameFileF = './data/popularNameF.txt' # 女性名来源文件
    19. gender = random.choice('男女') # 随机生成男(1)或女(0)
    20. person = personName(gender, lastNameFile, firstNameFileM, firstNameFileF) # 根据性别生成人名
    21. print(person) # 裴南云

    模拟出生日期

    1. import random
    2. import datetime
    3. def birthdate(): # 随机产生出生日期,返回8位字符串
    4. year = random.choice(range(1900, 2020))
    5. date = datetime.date.today()+datetime.timedelta(days=random.randint(1,366)) #月份和日期项
    6. return str(year) + date.strftime('%m%d') # 19840509
    7. if __name__ == '__main__':
    8. date = birthdate() # 随机生日
    9. print(date) # 20170402

    出生序号

    1. import random
    2. def orderNumber(gender):
    3. num = random.choice(range(1, 100))
    4. genderNum = random.choice('13579') if gender == '男' else random.choice('02468')
    5. return '{:02}'.format(num) + str(genderNum)
    6. if __name__ == '__main__':
    7. gender = random.choice('男女') # 随机生成男或女
    8. order = orderNumber(gender) # 出生序号
    9. print(order) # 239

    随机地区码,返回包含地区码与对应地区的字典:

    1. def area(areaFile): # 随机产生一个6位地区码
    2. area = {}
    3. with open(areaFile, 'r', encoding='utf-8') as data:
    4. for x in data:
    5. ls = x.strip().split(',')
    6. area[ls[0]] = ls[1] # 得到保存地区编码的字典
    7. return area
    8. if __name__ == '__main__':
    9. areaFile = './data/IDcode.txt'
    10. area = area(areaFile) # 读文件返回地区码字典
    11. print(area)
    12. # {'110000': '北京', '110101': '东城区', '110102': '西城区', '110105': '朝阳区',...}

    模拟身份证号码

    1. def id17(area,date,order): # 先拼接出17位的身份证号
    2. areaId = random.choice(list(area.keys()))
    3. return areaId + date + order
    4. def id17218(id17): # 计算校验位
    5. ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    6. ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    7. s = sum([int(id17[i]) * ls[i] for i in range(17)]) # 将数字与该位上的权值相乘放入列表并求和
    8. id18 = id17 + ecc[s % 11] # 以位权和对11取余为索引获得校验位上的字符
    9. return id18 # 函数返回值为18位的身份证号

    随机设定一个民族

    1. import random
    2. def nation(nationFile):
    3. with open(nationFile, 'r', encoding='utf-8') as data:
    4. nationName = data.readline().split()
    5. nation = random.choice(nationName)
    6. return nation[:-1]
    7. if __name__ == '__main__':
    8. nationFile = './data/nation.txt'
    9. nationality = nation(nationFile)
    10. print(nationality)

    模拟居住地址:

    1. def village(villageFile,area):
    2. with open(villageFile, 'r', encoding='utf-8') as data:
    3. village = data.readline().split()
    4. address = random.choice(village)
    5. building = random.choice(range(1, 30))
    6. door = random.choice(range(1, 7))
    7. floor = random.choice(range(1, 35))
    8. room = random.choice(range(1, 4))
    9. areaId = random.choice(list(area.keys()))
    10. province = area.get(areaId[:2]+'0000','')
    11. city = area.get(areaId[:4]+'00','')
    12. area = area[areaId]
    13. address = '{}{}{}{}{}栋{}单元{:02}{:02}室'.format(province,city,area,address,building,door,floor,room)
    14. return address

    检查是否来自湖北或出生于湖北:

    1. def checkHubei(id18,address):
    2. if id18[:4] == '4201' and ('武汉' in address) and ('湖北' in address):
    3. return '出生且居住于湖北武汉'
    4. elif id18[:2] == '42' and ('湖北' in address):
    5. return '出生且居住于湖北'
    6. elif id18[:2] == '42':
    7. return '出生于湖北'
    8. elif '武汉' in address and '湖北' in address:
    9. return '居住于湖北武汉'
    10. elif '湖北' in address:
    11. return '居住于湖北'
    12. else:
    13. return address

    完整参考代码:

    1. #=============================================
    2. # 作者: 武汉理工大学 赵广辉
    3. # 日期: 2020.05.20
    4. # Email:30849528@qq.com
    5. # 版权: 作者原创,版权所有,谢绝转载
    6. # 教材:Python语言及其应用
    7. #=============================================
    8. import random
    9. import datetime
    10. def person_name(gender_of_id, last_name_file, male_name_file, female_name_file):
    11. """接收性别、百家姓文件名、男性常用文件名、女性常用文件名为参数,随机抽取一个姓氏,根据性别随机抽取名字,返回表示姓名的字符串"""
    12. with open(last_name_file, 'r', encoding='utf-8') as data:
    13. last = [line.strip().replace(',', '').replace('。', '') for line in data]
    14. last1 = ''.join(last[:51])
    15. last2 = ''.join(last[51:])
    16. last = list(last1) + [last2[i * 2: i * 2 + 2] for i in range(len(last2) // 2)] # 得到姓的列表
    17. last_name = random.choice(last) # 随机一个姓
    18. with open(male_name_file, 'r', encoding='utf-8') as data:
    19. male_name = data.readline().split()
    20. with open(female_name_file, 'r', encoding='utf-8') as data:
    21. female_name = data.readline().split()
    22. first_name = random.choice(male_name) if gender_of_id == '男' else random.choice(female_name)
    23. return last_name + first_name
    24. def area_code(area_file):
    25. """传入参数为包含地区编码和地区名的文件名的字符串,以地区编码为键,地区名为值构建字典做为返回值"""
    26. area_of_birth = {}
    27. with open(area_file, 'r', encoding='utf-8') as data:
    28. for x in data:
    29. ls = x.strip().split(',')
    30. area_of_birth[ls[0]] = ls[1] # 得到保存地区编码的字典
    31. return area_of_birth
    32. def birthdate(): # 随机产生出生日期,返回8位字符串
    33. """在1900-2020间随机抽取一个数字做为出生年份,再随机生成一个合法的包含月和日的日期。
    34. 需要注意月份范围为1-12,1、3、5、7、8、10、12月的日期范围为1-31,
    35. 4、6、9、11的日期范围为1-30,闰年2月的日期范围为1-29,平年2月的日期范围为1-28。
    36. 年为4位字符串,月和日均为2位字符串,依序构成长度为8的字符串作为返回值,例如19840509 """
    37. year_of_birth = random.choice(range(1900, 2020))
    38. date_of_birth = datetime.date.today()+datetime.timedelta(days=random.randint(1, 366)) # 月份和日期项
    39. return str(year_of_birth) + date_of_birth.strftime('%m%d') # 19840509
    40. def order_number(gender_of_id):
    41. """接收表示性别的字符串为参数,随机抽取1-99之间的整数作为生出顺序号,
    42. 根据传入的性别随机抽取性别码,男性的性别码为偶数,女性的性别码为奇数"""
    43. num = random.choice(range(1, 100))
    44. gender_num = random.choice('13579') if gender_of_id == '男' else random.choice('02468')
    45. return '{:02}'.format(num) + str(gender_num)
    46. def id_of_17(birth_area, birth_date, birth_order):
    47. """接收地区码字典,出生日期和出生顺序号,随机抽取一个地区码,返回身份证号前17位的字符串。
    48. 需要注意的是,抽取地区码时,要避免抽取到省或地级市的编码"""
    49. area_id = random.choice([x for x in list(birth_area.keys()) if x[-2:] != '00']) # 避免抽到省市的编码
    50. return area_id + birth_date + birth_order
    51. def id17_to_18(id_number):
    52. """为身份证号增加校验位,接收身份证号码前17位,返回18位身份证号,校验码的计算方法:
    53. 1、将前面的身份证号码17位数分别乘以不同的系数。第一位到第十七位的系数分别为:7、9、10、5、8、4、2、1、6、3、7、9、10、5、8、4、2 ;
    54. 2、将这17位数字和系数相乘的结果相加;
    55. 3、用加出来和除以11,看余数是多少;
    56. 4、余数只可能有0、1、2、3、4、5、6、7、8、9、10这11个数字。
    57. 其分别对应的最后一位身份证的号码为1、0、X、9、8、7、6、5、4、3、2,其中的X是罗马数字10;
    58. 5、通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ;如果余数是10,身份证的最后一位号码就是2"""
    59. ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    60. ecc = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    61. s = sum([int(id_number[i]) * ls[i] for i in range(17)]) # 将数字与该位上的权值相乘放入列表并求和
    62. id_number = id_number + ecc[s % 11] # 以位权和对11取余为索引获得校验位上的字符
    63. return id_number # 函数返回值为18位的身份证号
    64. def village_of_live(village_file, area_of_live):
    65. """从village_file中随机选择一个小区名,从area_of_live中随机选择一个地区编码,并从中获取省、市、县(区)名。
    66. 楼栋号限制[1-30]中随机,单元号限制[1-7]中随机,楼层号限制[1-35]中随机,房间号限制[1-4]中随机。"""
    67. with open(village_file, 'r', encoding='utf-8') as data:
    68. village_live = data.readline().split()
    69. village = random.choice(village_live)
    70. building = random.choice(range(1, 30))
    71. door = random.choice(range(1, 7))
    72. floor = random.choice(range(1, 35))
    73. room = random.choice(range(1, 4))
    74. area_id = random.choice([x for x in list(area_of_live.keys()) if x[-2:] != '00']) # 避免抽到省市的编码
    75. province = area_of_live.get(area_id[:2]+'0000', '')
    76. city = area_of_live.get(area_id[:4]+'00', '')
    77. area = area_of_live[area_id]
    78. if area_id[:2] in ['11', '12', '31', '50']: # 北京市,上海市,天津市,重庆市
    79. address_of_live = f'{province}{area}'
    80. else:
    81. address_of_live = f'{province}{city}{area}'
    82. address_of_live = address_of_live + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
    83. return address_of_live, area_id
    84. def all_of_nation(nation_file):
    85. """传入参数为包含民族的文件名,从中随机抽取一个民族为返回值
    86. 需要注意的是,返回值里不包含'族'字,例如抽取'蒙古族',返回值为'蒙古'。 """
    87. with open(nation_file, 'r', encoding='utf-8') as data:
    88. nation_name = data.readline().split()
    89. nation = random.choice(nation_name)
    90. return nation[:-1]
    91. def print_id(full_name, gender_of_id, id_number, address, nation, birth_date):
    92. """按身份证正面的格式输出完整的身份信息,包括:
    93. 姓名
    94. 性别 民族
    95. 出生年月日
    96. 住址
    97. 公民身份证号"""
    98. print('-------------------------------------------------')
    99. print()
    100. print(f' 姓 名 {full_name}')
    101. print(f' 性 别 {gender_of_id} 民族 {nation}')
    102. print(f' 出 生 {birth_date[:4]} 年 {int(birth_date[4:6])} 月 {int(birth_date[6:])} 日')
    103. print(f' 住 址 {address[0]}')
    104. print()
    105. print(f' 公民身份证号码 {id_number}')
    106. print('-------------------------------------------------')
    107. # 获取和输出身份证注册地的省、市、县(区)
    108. def area_of_registration(id_number, id_code):
    109. """接收身份证号和居住地编码的字典为参数,返回持证人身份证注册地址的省市县(区)
    110. 需要注意的是,若持证人注册地为直辖市,则住址中无地级市,直接输出市和区,
    111. 例如:北京市朝阳区,其他地区格式例如:湖北省武汉市洪山区"""
    112. code = id_number[:6]
    113. province = id_code[code[:2] + '0000']
    114. city = id_code[code[:4] + '00']
    115. district = id_code[code]
    116. if code[:2] in ['11', '12', '31', '50']: # 北京市,上海市,天津市,重庆市
    117. return f'持证人出生于{province}{district}'
    118. else:
    119. return f'持证人出生于{province}{city}{district}'
    120. # 获取持证人居住地的省、市、县(区)
    121. def area_of_live(area_id, id_code):
    122. """接收居住地编码和身份证号为参数,返回持证人居住地址的省市县(区)
    123. 需要注意的是,若持证人居住地为直辖市,则住址中无地级市,直接输出市和区,
    124. 例如:北京市朝阳区,其他地区格式例如:湖北省武汉市洪山区"""
    125. province = id_code[area_id[:2] + '0000']
    126. city = id_code[area_id[:4] + '00']
    127. district = id_code[area_id]
    128. if area_id[:2] in ['11', '12', '31', '50']: # 北京市,上海市,天津市,重庆市
    129. return f'持证人居住于{province}{district}'
    130. else:
    131. return f'持证人居住于{province}{city}{district}'
    132. # 查验城市的编码
    133. def check_city_code(city_name, area_code):
    134. """接收一个字符串参数,表示城市名,返回值为该城市对应的地区编码,6位字符串"""
    135. for code, v in area_code.items():
    136. if v == city_name:
    137. return code
    138. # 查验持证人是否与指定的城市相关
    139. def check_city(id_number, city_name, city_code, area_of_live):
    140. """接收参数身份证号,查验城市名和城市编码,居住地信息,
    141. 若居住地与查验城市名相同,返回持证人居住于city_name市
    142. 否则若出生地与查验城市相同,返回持证人出生于city_name市
    143. 其他情况返回持证人与city_name无关联"""
    144. print(area_of_live)
    145. if city_name in area_of_live:
    146. return f'持证人居住于{city_name}'
    147. elif city_code[:4] == id_number[:4]:
    148. return f'持证人出生于{city_name}'
    149. else:
    150. return f'持证人与{city_name}无关联'
    151. # 根据身份证号输出性别与年龄
    152. def age_of_id(id_number):
    153. """接收身份证号为参数,返回值为持证人年龄和性别
    154. 年龄的计算方式为当前年份减出生年份"""
    155. currentYear = datetime.datetime.now().year
    156. gender = '男' if id_number[16] in '13579' else '女'
    157. age = currentYear - int(id_number[6:10])
    158. return gender, age
    159. if __name__ == '__main__':
    160. last_name_filename = './data/family names.txt' # 百家姓
    161. male_name_filename = './data/popularNameM.txt' # 男性名来源文件
    162. female_name_filename = './data/popularNameF.txt' # 女性名来源文件
    163. area_filename = './data/IDcode.txt' # 地区码
    164. village_filename = './data/villageName.txt' # 常用小区名
    165. nation_filename = './data/nation.txt' # 民族
    166. random.seed(19730516) # 随机数种子,用于自动评测
    167. gender = random.choice('男女') # 随机生成男(1)或女(0)
    168. person = person_name(gender, last_name_filename, male_name_filename, female_name_filename) # 根据性别生成人名
    169. area_number = area_code(area_filename) # 随机地区码字典
    170. date = birthdate() # 随机生日
    171. order = order_number(gender) # 随机出生序号
    172. id17 = id_of_17(area_number, date, order) # 拼接身份证号前17位
    173. id18 = id17_to_18(id17) # 加校验码成18位身份证号
    174. address_and_code = village_of_live(village_filename, area_number)
    175. nationality = all_of_nation(nation_filename)
    176. print_id(person, gender, id18, address_and_code, nationality, date)
    177. print(*age_of_id(id18))
    178. city_name = input()
    179. city_code = check_city_code(city_name, area_number)
    180. print(check_city(id18, city_name, city_code, address_and_code[0]))
    181. print(area_of_live(address_and_code[1], area_number))

    image.png
    以下代码可以模拟生成身份证号及相关信息
    验证出生地与住址是否为特定城市
    输出身份证信息
    将模拟产生的身份证写入到文件
    将文件中的每个人的身份信息写入二维码
    存在问题:
    为了完整保存出生城市与生活城市,假定每个城市都属于一个地级市,但由于部分城市属于省管县级市,缺少地级城市信息,而且没有规律,所以没加以处理,遇到问题时多运行几次程序也可以得到足够数量的虚拟身份信息。
    模拟身份证.csv
    西门晓晴.png

    # ------------      -------    --------    -----------    -----------
    # @File       : 7.4.3 模拟生成身份信息并查验身份实验模板.py
    # @Contact    : vasp@qq.com
    # @Copyright  : 2018-2025, Wuhan University of Technology
    # @Modify Time: 2021/4/27 16:56
    # @Author     : 赵广辉
    # @Version    : 1.0
    # @License    : 仅限用于Python程序设计基础实践教程(赵广辉,高等教育出版社)配套实验
    # ------------      -------    --------    -----------    -----------
    # 通过查验居民身份证可以掌握持证人的姓名、性别、出生日期、住址和公民身份证号码等信息,还可以获得居住后和出生地信息。
    # 疫情期间,需要通过查验身份证来实现对一些出生或居住在敏感地区的人进行监控,现在需要你开发这样一个系统,具有以下功能:
    # 1.为测试以上功能,模拟产生一个身份证上的全部信息。具体方法为
    # 1.1 模拟姓名,从百家姓中抽取一个姓,注意百家姓文件中前51行为单姓,51行后面为双字复姓。根据性别从男或女性常用名中取机抽取一个名字。
    # 1.2 模拟出生日期(限制1900-2020),性别随机男女、民族从56个民族中随机取一个
    # 1.3 模拟住址,省、市、县区随机,随机一个小区、100以内整数楼号、房间号格式为 a - b0c,a 为 1-8, b为 0-35,c 为 1-4
    # 1.4  模拟生成身份证号,出生序号随机。
    # 1.5 按身份证格式打印输出模拟产生的身份证
    # 2.输出年龄和性别
    # 3.获取和输出身份证注册地的省、市、县(区)
    # 4.获取持证人居住地的省、市、县(区)
    # 5.根据输入设置敏感地区,判定持证人是否为敏感地区常住人或是敏感地区出生者。
    
    import random
    import datetime
    import qrcode
    
    # {'性别': '男',
    #  '姓名': '缪心怡',
    #  '出生': '1910 年 7 月 9 日',
    #  '民族': '仫佬',
    #  '出生省市': '广西自治区', '出生地区': '桂林市', '出生县区': '七星区',
    #  '公民身份号码': '450305191007098298',
    #  '住址': '安徽省阜阳市阜南县北京财富中心27栋4单元2502室',
    #  '居住省市': '安徽省', '居住地区': '阜阳市', '居住县区': '阜南县'
    #  }
    
    
    def generate_id_number():
        """随机生成并返回一个18位身份证号,并将性别,出生区码,出生省市区和身份证号存入字典"""
        id_info_dict = {}
        id_info_dict = get_gender(id_info_dict)  # 为字典增加性别项
        order_num = order_number(id_info_dict['性别'])  # 产生出生序号,3位数字字符串
        id_info_dict = get_birthdate(id_info_dict)  # 为字典增加出生日期项,8位数字字符串
        area_code_dict = area_code_dic()  # 生成地区编码字典
        area_code_dict = get_area(area_code_dict, id_info_dict)  # 为字典增加出生省、市、区项,返回出生区码
        id_number_17 = area_code_dict['出生区码'] + id_info_dict['出生'] + order_num  # 17位身份证号
        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_17[i]) * ls[i] for i in range(17)])  # 将数字与该位上的权值相乘放入列表并求和
        id_number = id_number_17 + ecc[s % 11]  # 以位权和对11取余为索引获得校验位上的字符
        id_info_dict['公民身份号码'] = id_number
        return id_info_dict  # 函数保存身份号码的字典
    
    
    def generate_information(id_info_dict):
        """模拟产生身份信息,返回字典"""
        gender = id_info_dict['性别']
        id_info_dict = person_name(gender, id_info_dict)  # 为字典增加姓名项
        id_info_dict = get_nation(id_info_dict)  # 为字典增加民族项
        area_code_dict = area_code_dic()  # 生成地区编码字典
        id_info_dict = get_address(id_info_dict)
        return id_info_dict
    
    
    def get_gender(id_info_dict):
        """随机获取一个性别并返回"""
        gender = random.choice('男女')  # 随机生成男或女
        id_info_dict['性别'] = gender
        return id_info_dict
    
    
    def get_last_name():
        """读百家姓文件,随机选选一个姓并返回"""
        last_name_file = '../data/family names.txt'  # 百家姓
        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)  # 随机一个姓
        return last_name
    
    
    def get_first_name(gender):
        """读男女姓名文件,根据性别随机选取一个名字,返回字符串"""
        male_name_file = '../data/popularNameM.txt'  # 男性名来源文件
        female_name_file = '../data/popularNameF.txt'  # 女性名来源文件
        name_file = male_name_file if gender == '男' else female_name_file
        with open(name_file, 'r', encoding='utf-8') as data:
            male_name = data.readline().split()
        first_name = random.choice(male_name)
        return first_name
    
    
    def person_name(gender, id_info_dict):
        """last_name:姓,first_name:名字, 返回表示姓名的字符串。 """
        last_name = get_last_name()
        first_name = get_first_name(gender)
        full_name = last_name + first_name
        id_info_dict['姓名'] = full_name
        return id_info_dict
    
    
    def get_birthdate(id_info_dict):
        """在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  # 月份和日期项
        birthdate = date_of_birth.strftime("%Y%m%d")  # 19840509
        id_info_dict['出生'] = birthdate
        return id_info_dict
    
    
    def get_nation(id_info_dict):
        """读包含民族的文件,从中随机抽取一个民族为返回值。
        需要注意的是,返回值里不包含'族'字,例如抽取'蒙古族',返回值为'蒙古'。
        """
        nation_file = '../data/nation.txt'  # 民族
        with open(nation_file, 'r', encoding='utf-8') as data:
            nation_name = data.readline().split()
        nation = random.choice(nation_name)
        id_info_dict['民族'] = nation[:-1]
        return id_info_dict
    
    
    def area_code_dic():
        """ 以地区编码为键,地区名为值构建字典作为返回值。"""
        area_code = {}
        area_file = '../data/IDcode.txt'  # 地区码
        with open(area_file, 'r', encoding='utf-8') as data:
            for x in data:
                ls = x.strip().split(',')
                area_code[ls[0]] = ls[1]  # 得到保存地区编码的字典
        return area_code
    
    
    def get_area(area_code, id_info_dict):
        """
        @参数 area_code:地区码字典
        接收地区码字典,出生日期和出生顺序号,随机抽取一个地区码,为身份信息字典增加出生地区信息项。
        需要注意的是,抽取地区码时,要避免抽取到省或地级市的编码(最后2位编码为0)。
        """
        area_no_city = [x for x in area_code.keys() if x[-2:] != '00']
        area_id = random.choice(area_no_city)  # 避免抽到省市的编码
        id_info_dict['出生省市'] = area_code[area_id[:2] + '0000']
        id_info_dict['出生地区'] = area_code[area_id[:-2] + '00']
        id_info_dict['出生县区'] = area_code[area_id]
        id_info_dict['出生区码'] = area_id
        return id_info_dict
    
    
    def get_address(id_info_dict):
        """
        @ 参数 area_of_code:地区编码,字典类型
        返回居住地址,字符串
        从village_file中随机选择一个小区名,从area_of_code中随机选择一个地区编码,并从中获取省、市、
        县(区)名。楼栋号限制[1-30]中随机,单元号限制[1-7]中随机,楼层号限制[1-35]中随机,
        房间号限制[1-4]中随机。
        """
        area_code = area_code_dic()  # 生成地区编码字典
        village_file = '../data/villageName.txt'  # 常用小区名
        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_code.keys()) if x[-2:] != '00'])  # 避免抽到省市的编码
        province = area_code.get(area_id[:2] + '0000', '')
        city = area_code.get(area_id[:4] + '00', '')
        area = area_code[area_id]
        if area_id[:2] in ['11', '12', '31', '50']:  # 北京市,上海市,天津市,重庆市
            address_of_live = province + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
            city = ''
        else:
            address_of_live = city + f'{village}{building}栋{door}单元{floor:02}{room:02}室'
        id_info_dict['住址'] = address_of_live
        id_info_dict['居住省市'] = province
        id_info_dict['居住地区'] = city
        id_info_dict['居住县区'] = area
        return id_info_dict
    
    
    def order_number(gender):
        """接收性别为参数,随机抽取1-99之间的整数作为顺序号,根据性别随机抽取性别序号数字,男偶女奇"""
        num = random.choice(range(1, 100))
        # gender_num = random.choice('13579') if gender == '男' else random.choice('02468')
        if gender == '男':
            gender_num = random.choice('13579')
        else:
            gender_num = random.choice('02468')
        order = '{:02}'.format(num) + str(gender_num)
        return order
    
    
    def print_id(id_info_dict):
        """
        按身份证正面的格式输出完整的身份信息,包括:
        姓名
        性别   民族
        出生年月日
        住址
        公民身份号码"""
        date = id_info_dict["出生"]
        print('-------------------------------------------------')
        print()
        print(f'  姓  名  {id_info_dict["姓名"]}')
        print(f'  性  别  {id_info_dict["性别"]}   民族  {id_info_dict["民族"]}')
        print(f'  出  生  {date[:4]} 年 {int(date[4:6])} 月 {int(date[6:])} 日')
        print(f'  住  址  {id_info_dict["住址"]}')
        print()
        print(f'  公民身份号码 {id_info_dict["公民身份号码"]}')
        print('-------------------------------------------------')
    
    
    def area_of_registration(id_info_dict):
        """返回持证人出生的省市县(区)
        需要注意的是,若持证人注册地为直辖市,则住址中无地级市,直接输出市和区,例如:北京市朝阳区
        其他地区格式例如:湖北省武汉市洪山区。
        """
        return f'持证人出生于{id_info_dict["出生省市"]}{id_info_dict["出生地区"]}{id_info_dict["出生县区"]}'
    
    
    def area_of_live(id_info_dict):
        """返回持证人居住地址的省市县(区) """
        return f'持证人住址为{id_info_dict["居住省市"]}{id_info_dict["住址"]}'
    
    
    def check_city(city_name, id_info_dict):
        """
        @ 参数 city_name:查验城市名,字符串类型
        接收查验城市名,查验持证人是否与指定的城市相关
        若居住地与查验城市名相同,返回持证人居住于city_name市
        否则若出生地与查验城市相同,返回持证人出生于city_name市
        其他情况返回持证人与city_name无关联。
        """
        if city_name in id_info_dict['居住地区']:
            return f'持证人居住于{city_name}'
        elif city_name in id_info_dict['出生地区']:
            return f'持证人出生于{city_name}'
        else:
            return f'持证人与{city_name}无关联'
    
    
    def judge(id_info_dict):
        """输入一个字符串为参数,如果参数值为“姓名”,输出当前模拟身证上的姓名;
        如果参数是身份证号,输出当前模拟的身份证号的号码。如果参数值是“住址”,输出当前身份证号上的住址。
        如果参数值为“性别”,输出当前模拟身证上的性别;
        如果参数值为“姓名”,输出当前模拟身证上的姓名;
        如果参数值为“住址”,输出当前模拟身证上的住址;
        如果参数值为“身份证”,按身份证格式输出当前模拟身证上的全部信息;
        如果参数值为“查询”,,要求用户输入一个要查询的人名,再输入一个单词做为匹配词,
        根据输入设置敏感地区,判定持证人是否为敏感地区常住人或是敏感地区出生者。。"""
        while txt := input():
            if txt in ['姓名', '性别', '公民身份号码', '住址']:
                print(id_info_dict[txt])
            elif txt == '身份证':
                print_id(id_info_dict)
            elif txt == '查询':
                city_name = input()  # 输入敏感城市名
                relation = check_city(city_name, id_info_dict)
                print(relation)
            else:
                print('输入错误')
    
    
    def id_detail_csv(file, id_info_dict):
        """将身份证信息按指定的顺序排序后写入到文件中"""
        order = ['姓名', '性别', '出生', '民族', '公民身份号码', '住址', '出生省市', '出生地区', '出生县区', '出生区码', '居住省市', '居住地区', '居住县区']
        title = ','.join(order) + '\n'
        data_ls = [id_info_dict[key] for key in order]
        data = ','.join(data_ls) + '\n'
        with open(file, 'a+', encoding="utf-8") as f:
            f.seek(0)  # 指针移动文件开头,判断文件是否为空
            if f.readline()[:2] == '姓名':  # 读第一行,若开头文字是'姓名',则有数据,略过标题行
                f.seek(2)  # 指针移动文件末尾
                f.write(data)
            else:
                f.write(title)
                f.write(data)
    
    
    def faker_id(n):
        """生成n个虚拟身份信息,写入到csv文件中"""
        filename = '模拟身份证.csv'
        for i in range(n):
            id_detail = generate_id_number()  # 生成一个身份证号存入字典
            id_detail = generate_information(id_detail)  # 为字典补充信息
            id_detail_csv(filename, id_detail)
    
    
    def add_color(file):
        """读文件中的数据,为数据赋健康码,转为元素为字典的列表返回"""
        with open(file, 'r', encoding='utf-8') as fr:
            id_info = [line.strip().split(',') for line in fr]
        id_info[0].append('健康码')
        for x in id_info[1:]:
            color = random.choice(['红码', '绿码', '黄码'])
            x.append(color)
        for i in range(1, len(id_info[1:])):
            id_info[i] = dict(zip(id_info[0], id_info[i]))
        return id_info[1:]
    
    
    def make_qrcode(id_info):
        """为每一个人生成一个二维码"""
        path = './二维码/'
        for x in id_info:
            img = qrcode.make(str(x))  # 调用qrcode的make()
            print(f"正在生成{x['姓名']}的二维码...")
            img.save(path + x['姓名'] + '.png')
    
    
    if __name__ == '__main__':
        # random.seed()  # 随机数种子,不用于自动评测时注释掉此行
        # id_detail = generate_id_number()  # 生成一个身份证号存入字典
        # id_detail = generate_information(id_detail) # 为字典补充信息
        # print_id(id_detail)  # 打印身份证
        # judge(id_detail)
        # print(id_detail)
        # n = int(input())
        # faker_id(n)
        filename = '模拟身份证.csv'
        id_with_color = add_color(filename)
        make_qrcode(id_with_color)