博客> 身份证验证
身份证验证
2018-10-19 04:42 评论:0 阅读:507 易_君
ios oc 身份证

// // VerifyRegexTool.h // Service // // Created by Mac on 2017/6/29. // Copyright © 2017年 Apple. All rights reserved. //

pragma mark --.h文件

import

@interface VerifyRegexTool : NSObject

//验证是否为空

  • (BOOL)verifyIsNotEmpty:(NSString *)value; //验证身份证
  • (BOOL)verifyIDCardNumber:(NSString *)value;

@end

/**

  • 理论部分:

    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岁,需要另行检查,不应放在身份证校验里面。 长度必须是18位,前17位必须是数字,第十八位可以是数字或X(校验时不区分大小写) 前两位必须是以下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 第7到第14位出生年月日。第7到第10位为出生年份;11到12位表示月份,范围为01~12;13到14位为合法的日期,比如月份是04,范围应是01~30 第17位表示性别,必须是0或1,0表示女,1表示男 第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 第7位必须为1,第8位必须为9,即:出生年份的前两位必须是19

  • */

/**/

pragma mark --.m文件

// // VerifyRegexTool.m // Service // // Created by Mac on 2017/6/29. // Copyright © 2017年 Apple. All rights reserved. //

import "VerifyRegexTool.h"

@implementation VerifyRegexTool

//验证是否不为空

  • (BOOL)verifyIsNotEmpty:(NSString *)value { value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

    NSInteger length =0;

    if (!value) {

    return NO;

    }else {

    length = value.length;
    
    if (length !=15 && length !=18) {
    
        return  NO;
    }

    }

    return YES; }

/* 验证身份证 必须满足以下规则

  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]]; }

+(BOOL)validateIdentityCard:(NSString *)sPaperId { if ([sPaperId length] != 18) { return NO; }

NSString *carid = sPaperId;

long lSumQT =0;

//加权因子
int R[] ={7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

//校验码
unsigned char sChecker[11]={'1','0','X', '9', '8', '7', '6', '5', '4', '3', '2'};

//判断地区码

NSString * sProvince = [carid substringToIndex:2];

if (![self areaCode:sProvince]) {

    return NO;

}

//判断年月日是否有效
//年份

int strYear = [[self getStringWithRange:carid Value1:6 Value2:4] intValue];

//月份

int strMonth = [[self getStringWithRange:carid Value1:10 Value2:2] intValue];

//日

int strDay = [[self getStringWithRange:carid Value1:12 Value2:2] intValue];

NSTimeZone *localZone = [NSTimeZone localTimeZone];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateStyle:NSDateFormatterMediumStyle];

[dateFormatter setTimeStyle:NSDateFormatterNoStyle];

[dateFormatter setTimeZone:localZone];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];

NSDate *date=[dateFormatter dateFromString:[NSString stringWithFormat:@"%d-%d-%d 12:01:01",strYear,strMonth,strDay]];

if (date == nil) {
    return NO;
}

const char *PaperId  = [carid UTF8String];

//检验长度

if( 18 != strlen(PaperId)) return -1;

//校验数字

for (int i=0; i<18; i++){

    if ( !isdigit(PaperId[i]) && !(('X' == PaperId[i] || 'x' == PaperId[i]) && 17 == i) ){
        return NO;
    }
}

//验证最末的校验码

for (int i=0; i<=16; i++){
    lSumQT += (PaperId[i]-48) * R[i];
}

if (sChecker[lSumQT] != PaperId[17] ){
    return NO;
}
return YES;

}

+(NSString )getStringWithRange:(NSString )str Value1:(NSInteger *)value1 Value2:(NSInteger )value2;{ return [str substringWithRange:NSMakeRange(value1,value2)]; }

+(BOOL)areaCode:(NSString *)code{

NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];

[dic setObject:@"北京" forKey:@"11"];

[dic setObject:@"天津" forKey:@"12"];

[dic setObject:@"河北" forKey:@"13"];

[dic setObject:@"山西" forKey:@"14"];

[dic setObject:@"内蒙古" forKey:@"15"];

[dic setObject:@"辽宁" forKey:@"21"];

[dic setObject:@"吉林" forKey:@"22"];

[dic setObject:@"黑龙江" forKey:@"23"];

[dic setObject:@"上海" forKey:@"31"];

[dic setObject:@"江苏" forKey:@"32"];

[dic setObject:@"浙江" forKey:@"33"];

[dic setObject:@"安徽" forKey:@"34"];

[dic setObject:@"福建" forKey:@"35"];

[dic setObject:@"江西" forKey:@"36"];

[dic setObject:@"山东" forKey:@"37"];

[dic setObject:@"河南" forKey:@"41"];

[dic setObject:@"湖北" forKey:@"42"];

[dic setObject:@"湖南" forKey:@"43"];

[dic setObject:@"广东" forKey:@"44"];

[dic setObject:@"广西" forKey:@"45"];

[dic setObject:@"海南" forKey:@"46"];

[dic setObject:@"重庆" forKey:@"50"];

[dic setObject:@"四川" forKey:@"51"];

[dic setObject:@"贵州" forKey:@"52"];

[dic setObject:@"云南" forKey:@"53"];

[dic setObject:@"西藏" forKey:@"54"];

[dic setObject:@"陕西" forKey:@"61"];

[dic setObject:@"甘肃" forKey:@"62"];

[dic setObject:@"青海" forKey:@"63"];

[dic setObject:@"宁夏" forKey:@"64"];

[dic setObject:@"新疆" forKey:@"65"];

[dic setObject:@"台湾" forKey:@"71"];

[dic setObject:@"香港" forKey:@"81"];

[dic setObject:@"澳门" forKey:@"82"];

[dic setObject:@"国外" forKey:@"91"];

if ([dic objectForKey:code] == nil) {

    return NO;

}

return YES;

}

@end

收藏
0
sina weixin mail 回到顶部