理论部分:

15位身份证号码=6位地区代码+6位生日+3位编号
18位身份证号码=6位地区代码+8位生日+3位编号+1位检验码

各省市地区国家代码前两位代码是:     
  北京   11   吉林   22     福建   35   广东   44   云南   53   天津   12   黑龙江   23     江西   36   广西   45     西藏   54   河北   13     上海   31     山东   37     海南   46     陕西   61     山西   14     江苏   32     河南   41     重庆   50   
    甘肃   62   内蒙古   15     浙江   33     湖北   42     四川   51     青海   63       辽宁   21     安徽   34     湖南   43     贵州   52     宁夏   64     新疆   65     台湾   71     香港   81     澳门   82     国外   91

18位身份证标准在国家质量技术监督局于1999年7月1日实施的GB11643-1999《公民身份号码》中做了明确规定。

GB11643-1999《公民身份号码》为GB11643-1989《社会保障号码》的修订版,其中指出将原标准名称“社会保障号码”更名为“公民身份号码”,另外GB11643-1999《公民身份号码》从实施之日起代替GB11643-1989。

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

1. 地址码:表示编码对象常住户口所在县(市、旗、区)的行政区划代码,按GB/T2260的规定执行。

2. 出生日期码:表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日分别用4位、2位、2位数字表示,之间不用分隔符。

3. 顺序码:表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。

校验的计算方式:

1. 对前17位数字本体码加权求和
公式为:S = Sum(Ai * Wi), i = 0, ... , 16
其中Ai表示第i位置上的身份证号码数字值,Wi表示第i位置上的加权因子,其各位对应的值依次为: 
              7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2

2. 以11对计算结果取模
Y = mod(S, 11)

3. 根据模的值得到对应的校验码对应关系为:
  Y值: 0 1 2 3 4 5 6 7 8 9 10
校验码: 1 0 X 9 8 7 6 5 4 3 2


说明:

  • 在ios项目的开发中可能很多地方都需要用到身份证校验,一般在开发的时候很多人都是直接百度去网上荡相关的正则表达式和校验代码,但是网上疯狂 粘贴复制的校验代码本身也可能并不准确,可能会有风险,比如2013年1月1号起停止使用15位的身份证,网上的身份证校验普遍支持15位的号码。
  • 在开发过程中,进行类似处理的时候,还是需要一些甄别的能力的,当然也要考虑自己的项目的实际情况。该文贴出了最近项目中使用到得身份证校验代码,以方便有需要的人“谨慎”获取。

一、规则

下面是iOS身份证校验规则,对于第6点就值得商榷,按道理出生年份前两位是20也应该是合理的。如果要校验投保人需要年满18岁,需要另行检查,不应放在身份证校验里面。
  1. 长度必须是18位,前17位必须是数字,第十八位可以是数字或X(校验时不区分大小写)
  2. 前两位必须是以下35种情形中的一种: 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,71,81,82,91
  3. 第7到第14位出生年月日。第7到第10位为出生年份;11到12位表示月份,范围为01~12;13到14位为合法的日期,比如月份是04,范围应是01~30
  4. 第17位表示性别,必须是0或1,0表示女,1表示男
  5. 第18位为前17位的校验位 算法如下:
    • 总和 = (n1 + n11) * 7 + (n2 + n12) * 9 + (n3 + n13) * 10 + (n4 + n14) * 5 + (n5 + n15) * 8 + (n6 + n16) * 4 + (n7 + n17) * 2 + n8 + n9 * 6 + n10 * 3,其中n1表示1位数字,其它类似
    • 用总和除以11,看余数是多少, 余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2
  6. 第7位必须为1,第8位必须为9,即:出生年份的前两位必须是19

二、代码示例:

对于这种需要在很多地方都用到的代码,可以使用一个工具类或者是分类来写。这里把校验的代码写在了一个工具类中。

VerifyRegexTool.h文件代码:

#import <Foundation/Foundation.h>@interface VerifyRegexTool : NSObject+ (BOOL)verifyIsNotEmpty:(NSString *)str;   //验证是否不为空+ (BOOL)verifyText:(NSString *)text withRegex:(NSString *)regex;    //正则验证+ (BOOL)verifyIDCardNumber:(NSString *)value; //验证身份证+ (BOOL)verifyCardNumberWithSoldier:(NSString *)value;   //验证军官证或警官证+ (BOOL)verifyIDCardHadAdult:(NSString *)card;  //验证身份证是否成年且小于100岁****这个方法中不做身份证校验,请确保传入的是正确身份证+ (BOOL)verifyIDCardMoreThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType; //验证身份证加上指定天数是否大于指定number的类型+ (BOOL)verifyIDCardLessThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType;  //验证身份证是否小于指定number的类型+ (NSString *)getIDCardBirthday:(NSString *)card;   //得到身份证的生日****这个方法中不做身份证校验,请确保传入的是正确身份证
+ (NSInteger)getIDCardSex:(NSString *)card;   //得到身份证的性别(1男0女)****这个方法中不做身份证校验,请确保传入的是正确身份证@end

VerifyRegexTool.m文件代码:

#import "VerifyRegexTool.h"@implementation VerifyRegexTool//验证是否不为空
+ (BOOL)verifyIsNotEmpty:(NSString *)str
{if (!str) return NO;str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];if (![str isEqualToString:@""]) {return YES;} else {return NO;}
}//正则验证
+ (BOOL)verifyText:(NSString *)text withRegex:(NSString *)regex
{return [[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isMatchedByRegex:regex];
}//验证身份证
//必须满足以下规则
//1. 长度必须是18位,前17位必须是数字,第十八位可以是数字或X
//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,71,81,82,91
//3. 第7到第14位出生年月日。第7到第10位为出生年份;11到12位表示月份,范围为01-12;13到14位为合法的日期
//4. 第17位表示性别,双数表示女,单数表示男
//5. 第18位为前17位的校验位
//算法如下:
//(1)校验和 = (n1 + n11) * 7 + (n2 + n12) * 9 + (n3 + n13) * 10 + (n4 + n14) * 5 + (n5 + n15) * 8 + (n6 + n16) * 4 + (n7 + n17) * 2 + n8 + n9 * 6 + n10 * 3,其中n数值,表示第几位的数字
//(2)余数 = 校验和 % 11
//(3)如果余数为0,校验位应为1,余数为1到10校验位应为字符串“0X98765432”(不包括分号)的第余数位的值(比如余数等于3,校验位应为9)
//6. 出生年份的前两位必须是19或20
+ (BOOL)verifyIDCardNumber:(NSString *)value
{value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];if ([value length] != 18) {return NO;}NSString *mmdd = @"(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8])))";NSString *leapMmdd = @"0229";NSString *year = @"(19|20)[0-9]{2}";NSString *leapYear = @"(19|20)(0[48]|[2468][048]|[13579][26])";NSString *yearMmdd = [NSString stringWithFormat:@"%@%@", year, mmdd];NSString *leapyearMmdd = [NSString stringWithFormat:@"%@%@", leapYear, leapMmdd];NSString *yyyyMmdd = [NSString stringWithFormat:@"((%@)|(%@)|(%@))", yearMmdd, leapyearMmdd, @"20000229"];NSString *area = @"(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|82|[7-9]1)[0-9]{4}";NSString *regex = [NSString stringWithFormat:@"%@%@%@", area, yyyyMmdd  , @"[0-9]{3}[0-9Xx]"];NSPredicate *regexTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];if (![regexTest evaluateWithObject:value]) {return NO;}int summary = ([value substringWithRange:NSMakeRange(0,1)].intValue + [value substringWithRange:NSMakeRange(10,1)].intValue) *7+ ([value substringWithRange:NSMakeRange(1,1)].intValue + [value substringWithRange:NSMakeRange(11,1)].intValue) *9+ ([value substringWithRange:NSMakeRange(2,1)].intValue + [value substringWithRange:NSMakeRange(12,1)].intValue) *10+ ([value substringWithRange:NSMakeRange(3,1)].intValue + [value substringWithRange:NSMakeRange(13,1)].intValue) *5+ ([value substringWithRange:NSMakeRange(4,1)].intValue + [value substringWithRange:NSMakeRange(14,1)].intValue) *8+ ([value substringWithRange:NSMakeRange(5,1)].intValue + [value substringWithRange:NSMakeRange(15,1)].intValue) *4+ ([value substringWithRange:NSMakeRange(6,1)].intValue + [value substringWithRange:NSMakeRange(16,1)].intValue) *2+ [value substringWithRange:NSMakeRange(7,1)].intValue *1 + [value substringWithRange:NSMakeRange(8,1)].intValue *6+ [value substringWithRange:NSMakeRange(9,1)].intValue *3;NSInteger remainder = summary % 11;NSString *checkBit = @"";NSString *checkString = @"10X98765432";checkBit = [checkString substringWithRange:NSMakeRange(remainder,1)];// 判断校验位return [checkBit isEqualToString:[[value substringWithRange:NSMakeRange(17,1)] uppercaseString]];
}//验证军官证或警官证
//必须是下面两种格式中的一种
//格式一:4到20位数字
//格式二:大于或等于10位并且小于等于20位(中文按两位),并满足以下规则
//1)必须有“字第”两字
//2)“字第”前面有至少一个字符
//3)“字第”后是4位以上数字
+ (BOOL)verifyCardNumberWithSoldier:(NSString *)value
{NSString *s1 = @"^\\d*$";NSString *s2 = @"^.{1,}字第\\d{4,}$";//NSString *s3 = @"^([A-Za-z0-9\\u4e00-\\u9fa5])*$";value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];if ([VerifyRegexTool verifyText:value withRegex:s1]) {NSString *s11 = @"^\\d{4,20}$";return [value isMatchedByRegex:s11];} else if ([self lengthUsingChineseCharacterCountByTwo:value] >= 10&& [self lengthUsingChineseCharacterCountByTwo:value] <= 20) {return [value isMatchedByRegex:s2];}return NO;
}+ (NSUInteger)lengthUsingChineseCharacterCountByTwo:(NSString *)string{NSUInteger count = 0;for (NSUInteger i = 0; i< string.length; ++i) {if ([string characterAtIndex:i] < 256) {count++;} else {count += 2;}}return count;
}//验证身份证是否成年且小于100岁****这个方法中不做身份证校验,请确保传入的是正确身份证
+ (BOOL)verifyIDCardHadAdult:(NSString *)card
{NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日//转换为****-**-**birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];NSDate *dateBirtday = [NSDate dateFromString:birtday];NSInteger year = [[NSDate date] getIntervalTime:dateBirtday withDateType:DateTypeYear];   //得到年数if (year >= 18 && year < 100) {return YES;} else {return NO;}}//验证身份证加上指定天数是否大于指定number的类型
+ (BOOL)verifyIDCardMoreThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType {NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日//转换为****-**-**birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];NSDate *dateBirtday = [NSDate dateFromString:birtday];NSDate *today = [NSDate dateFromStringWithoutTime:[[NSDate date] strDate]];NSDate *pointDate = [today dateByAddingTimeInterval:interval];//tempDate为number后的日期NSDate *tempDate = [pointDate dateAddNumber:-number withDateType:dateType];  //临界日期if ([dateBirtday earlierDate:tempDate] == dateBirtday) {  //如果生日+指定天数大雨tempdate,则通过return YES;} else {return NO;}
}//验证身份证加上指定天数是否小于指定number的类型
+ (BOOL)verifyIDCardLessThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType
{NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日//转换为****-**-**birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];NSDate *dateBirtday = [NSDate dateFromString:birtday];NSDate *today = [NSDate dateFromStringWithoutTime:[[NSDate date] strDate]];NSDate *pointDate = [today dateByAddingTimeInterval:interval];//tempDate为number后的日期NSDate *tempDate = [pointDate dateAddNumber:-number withDateType:dateType];  //临界日期if ([tempDate earlierDate:dateBirtday] == tempDate) {  //如果生日+指定天数小于tempdate,则通过return YES;} else {return NO;}
}//得到身份证的生日****这个方法中不做身份证校验,请确保传入的是正确身份证
+ (NSString *)getIDCardBirthday:(NSString *)card {card = [card stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];if ([card length] != 18) {return nil;}NSString *birthady = [NSString stringWithFormat:@"%@年%@月%@日",[card substringWithRange:NSMakeRange(6,4)], [card substringWithRange:NSMakeRange(10,2)], [card substringWithRange:NSMakeRange(12,2)]];return birthady;
}//得到身份证的性别(1男0女)****这个方法中不做身份证校验,请确保传入的是正确身份证
+ (NSInteger)getIDCardSex:(NSString *)card {card = [card stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];NSInteger defaultValue = 0;if ([card length] != 18) {return defaultValue;}NSInteger number = [[card substringWithRange:NSMakeRange(16,1)] integerValue];if (number % 2 == 0) {  //偶数为女return 0;} else {return 1;}
}@end

身份证校验调用示例

if (![VerifyRegexTool verifyIDCardNumber:self.IdentityCardNOTextfield.text]) {   //验证身份证是否真实[self showMessageHUD:@"请输入正确的身份证号码!" withTimeInterval:kShowMessageTime];return;
}

iOS之身份证的正则校验相关推荐

  1. iOS之身份证号码全校验与校验位自动补全

    在项目中进行身份证号码的校验,首先有必要了解一下居民身份证的基本构成: 长度必须是18位,前17位必须是数字,第十八位可以是数字或X: 前两位必须是以下情形中的一种:11.12.13.14.15.21 ...

  2. 身份证、手机号、邮箱、银行卡、企业税号等正则校验

    身份证号正则校验: 前6位 第一位1到9范围 后5位 数字 /^[1-9]\d{5}/ 年份4位 开头两位 18 or 19 or 20 后面2位数字 /(18|19|20)\d{2}/ 月份2位 1 ...

  3. vue身份证正则校验的2种类型

    项目场景: vue项目中身份证号码设置了校验,但是在验收的时候还可以输入错误的身份证号码.依旧通过了校验,发现是校验规则不够严格.替换一种新的校验方式 问题描述: 旧的正则校验不够严谨,可以输入合法但 ...

  4. vue身份证正则校验

    对身份证号码进行正则校验 let regs = /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|3 ...

  5. 身份证真实性校验js、mini ui身份证长度正则验证

    身份证号码真实性校验 <input type="text" value="请输入身份证号" id="cards" > <b ...

  6. java 身份证正则校验工具类

    import java.text.SimpleDateFormat; import java.util.Date;/** * 验证身份证号码 身份证号码, 可以解析身份证号码的各个字段, * 以及验证 ...

  7. 探究from表单的身份证号码的校验逻辑 javascript

    start 最近番茄学习前端八股文,学的有些乏味了.随即在应用商店下载了几个小游戏,准备把玩放松一下. 众所周知,现在玩游戏都是要身份证实名认证的,但是我又有精神洁癖,不想把自己的身份证提供给这种小作 ...

  8. java身份证格式强校验

    身份证格式强校验 import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern;import org.a ...

  9. 常用的手机号,身份号正则校验

    常用的手机号,身份号正则校验 手机号的正则校验: let tel = 12345678901; /^1[34578]\d{9}$/.test(tel): 返回值为true和false: functio ...

最新文章

  1. 如果你的云服务商倒闭该怎么办?
  2. Android组件化打造知乎日报系列(一)—— 项目架构搭建
  3. 抽象类在ASP.NET的学习与应用
  4. 从源码分析DEARGUI之add_slider_float-4和add_slider_int-4
  5. Sizeof与Strlen的区别与联系
  6. 掌握Angular2的服务(service)
  7. 【形式化方法:VDM++系列】4.VDM实战1——铁路费用计算
  8. LAMP构架概述及相关服务的搭建(附带搭建论坛实验)
  9. android7.1 shotcuts,Android N App Shotcuts 学习
  10. js插件编写常用工具函数及格式
  11. 「代码随想录」本周学习小结!(动态规划系列四)
  12. 2个YUV视频 拼接技术
  13. centos linux引导修复_CentOs7 修复 引导启动
  14. h5自我介绍作品_自我介绍h5模板
  15. 微软的产品激活中心电话
  16. VastBase账户锁The account has been locked
  17. GraphPad Prism 中文版 科研绘图工具
  18. oracle 菜单不见了,桌面任务栏不见了 - 电脑任务栏不见了的解决办法 - 安全专题...
  19. MongoDB分片集群搭建
  20. 去处word红色波浪线

热门文章

  1. socket:10038错误
  2. python小学生编程小游戏打地鼠turtle
  3. php scada,scada系统是什么
  4. 物联网安全威胁与解决方案调研
  5. 防范IFEO映像劫持
  6. 计算机基础 CMOS
  7. Dubbo host配置映射内网IP导致消费者无法连接到生产者提供的服务详解
  8. Android 强制应用全局横屏或竖屏
  9. Linux JKD1.8 安装及配置
  10. 计算机组成原理实验二 存储器实验