zoukankan      html  css  js  c++  java
  • iOS开发实用技巧—身份证的正则校验

    iOS开发实用技巧—身份证的正则校验

    说明:

    • 在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文件代码:

    复制代码
     1 #import <Foundation/Foundation.h>
     2 
     3 @interface VerifyRegexTool : NSObject
     4 
     5 + (BOOL)verifyIsNotEmpty:(NSString *)str;   //验证是否不为空
     6 
     7 + (BOOL)verifyText:(NSString *)text withRegex:(NSString *)regex;    //正则验证
     8 
     9 + (BOOL)verifyIDCardNumber:(NSString *)value; //验证身份证
    10 
    11 + (BOOL)verifyCardNumberWithSoldier:(NSString *)value;   //验证军官证或警官证
    12 
    13 + (BOOL)verifyIDCardHadAdult:(NSString *)card;  //验证身份证是否成年且小于100岁****这个方法中不做身份证校验,请确保传入的是正确身份证
    14 
    15 + (BOOL)verifyIDCardMoreThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType; //验证身份证加上指定天数是否大于指定number的类型
    16 
    17 + (BOOL)verifyIDCardLessThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType;  //验证身份证是否小于指定number的类型
    18 
    19 
    20 + (NSString *)getIDCardBirthday:(NSString *)card;   //得到身份证的生日****这个方法中不做身份证校验,请确保传入的是正确身份证
    21 + (NSInteger)getIDCardSex:(NSString *)card;   //得到身份证的性别(1男0女)****这个方法中不做身份证校验,请确保传入的是正确身份证
    22 
    23 @end
    复制代码

    VerifyRegexTool.m文件代码:

    复制代码
      1 #import "VerifyRegexTool.h"
      2 
      3 @implementation VerifyRegexTool
      4 
      5 //验证是否不为空
      6 + (BOOL)verifyIsNotEmpty:(NSString *)str
      7 {
      8     if (!str) return NO;
      9     
     10     str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
     11     if (![str isEqualToString:@""]) {
     12         return YES;
     13     } else {
     14         return NO;
     15     }
     16 }
     17 
     18 //正则验证
     19 + (BOOL)verifyText:(NSString *)text withRegex:(NSString *)regex
     20 {
     21     return [[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isMatchedByRegex:regex];
     22 }
     23 
     24 //验证身份证
     25 //必须满足以下规则
     26 //1. 长度必须是18位,前17位必须是数字,第十八位可以是数字或X
     27 //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
     28 //3. 第7到第14位出生年月日。第7到第10位为出生年份;11到12位表示月份,范围为01-12;13到14位为合法的日期
     29 //4. 第17位表示性别,双数表示女,单数表示男
     30 //5. 第18位为前17位的校验位
     31 //算法如下:
     32 //(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数值,表示第几位的数字
     33 //(2)余数 = 校验和 % 11
     34 //(3)如果余数为0,校验位应为1,余数为1到10校验位应为字符串“0X98765432”(不包括分号)的第余数位的值(比如余数等于3,校验位应为9)
     35 //6. 出生年份的前两位必须是19或20
     36 + (BOOL)verifyIDCardNumber:(NSString *)value
     37 {
     38     value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
     39     if ([value length] != 18) {
     40         return NO;
     41     }
     42     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])))";
     43     NSString *leapMmdd = @"0229";
     44     NSString *year = @"(19|20)[0-9]{2}";
     45     NSString *leapYear = @"(19|20)(0[48]|[2468][048]|[13579][26])";
     46     NSString *yearMmdd = [NSString stringWithFormat:@"%@%@", year, mmdd];
     47     NSString *leapyearMmdd = [NSString stringWithFormat:@"%@%@", leapYear, leapMmdd];
     48     NSString *yyyyMmdd = [NSString stringWithFormat:@"((%@)|(%@)|(%@))", yearMmdd, leapyearMmdd, @"20000229"];
     49     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}";
     50     NSString *regex = [NSString stringWithFormat:@"%@%@%@", area, yyyyMmdd  , @"[0-9]{3}[0-9Xx]"];
     51     
     52     NSPredicate *regexTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
     53     if (![regexTest evaluateWithObject:value]) {
     54         return NO;
     55     }
     56     int summary = ([value substringWithRange:NSMakeRange(0,1)].intValue + [value substringWithRange:NSMakeRange(10,1)].intValue) *7
     57             + ([value substringWithRange:NSMakeRange(1,1)].intValue + [value substringWithRange:NSMakeRange(11,1)].intValue) *9
     58             + ([value substringWithRange:NSMakeRange(2,1)].intValue + [value substringWithRange:NSMakeRange(12,1)].intValue) *10
     59             + ([value substringWithRange:NSMakeRange(3,1)].intValue + [value substringWithRange:NSMakeRange(13,1)].intValue) *5
     60             + ([value substringWithRange:NSMakeRange(4,1)].intValue + [value substringWithRange:NSMakeRange(14,1)].intValue) *8
     61             + ([value substringWithRange:NSMakeRange(5,1)].intValue + [value substringWithRange:NSMakeRange(15,1)].intValue) *4
     62             + ([value substringWithRange:NSMakeRange(6,1)].intValue + [value substringWithRange:NSMakeRange(16,1)].intValue) *2
     63             + [value substringWithRange:NSMakeRange(7,1)].intValue *1 + [value substringWithRange:NSMakeRange(8,1)].intValue *6
     64             + [value substringWithRange:NSMakeRange(9,1)].intValue *3;
     65     NSInteger remainder = summary % 11;
     66     NSString *checkBit = @"";
     67     NSString *checkString = @"10X98765432";
     68     checkBit = [checkString substringWithRange:NSMakeRange(remainder,1)];// 判断校验位
     69     return [checkBit isEqualToString:[[value substringWithRange:NSMakeRange(17,1)] uppercaseString]];
     70 }
     71 
     72 //验证军官证或警官证
     73 //必须是下面两种格式中的一种
     74 //格式一:4到20位数字
     75 //格式二:大于或等于10位并且小于等于20位(中文按两位),并满足以下规则
     76 //1)必须有“字第”两字
     77 //2)“字第”前面有至少一个字符
     78 //3)“字第”后是4位以上数字
     79 + (BOOL)verifyCardNumberWithSoldier:(NSString *)value
     80 {
     81     NSString *s1 = @"^\d*$";
     82     NSString *s2 = @"^.{1,}字第\d{4,}$";
     83     //NSString *s3 = @"^([A-Za-z0-9\u4e00-\u9fa5])*$";
     84     value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
     85     if ([VerifyRegexTool verifyText:value withRegex:s1]) {
     86         NSString *s11 = @"^\d{4,20}$";
     87         return [value isMatchedByRegex:s11];
     88     } else if ([self lengthUsingChineseCharacterCountByTwo:value] >= 10
     89                && [self lengthUsingChineseCharacterCountByTwo:value] <= 20) {
     90         return [value isMatchedByRegex:s2];
     91     }
     92     
     93     return NO;
     94 }
     95 
     96 + (NSUInteger)lengthUsingChineseCharacterCountByTwo:(NSString *)string{
     97     NSUInteger count = 0;
     98     for (NSUInteger i = 0; i< string.length; ++i) {
     99         if ([string characterAtIndex:i] < 256) {
    100             count++;
    101         } else {
    102             count += 2;
    103         }
    104     }
    105     return count;
    106 }
    107 
    108 //验证身份证是否成年且小于100岁****这个方法中不做身份证校验,请确保传入的是正确身份证
    109 + (BOOL)verifyIDCardHadAdult:(NSString *)card
    110 {
    111     NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日
    112     //转换为****-**-**
    113     birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];
    114     birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];
    115     birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];
    116     birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];
    117     NSDate *dateBirtday = [NSDate dateFromString:birtday];
    118     NSInteger year = [[NSDate date] getIntervalTime:dateBirtday withDateType:DateTypeYear];   //得到年数
    119     
    120     if (year >= 18 && year < 100) {
    121         return YES;
    122     } else {
    123         return NO;
    124     }
    125     
    126 }
    127 
    128 //验证身份证加上指定天数是否大于指定number的类型
    129 + (BOOL)verifyIDCardMoreThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType {
    130     NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日
    131     //转换为****-**-**
    132     birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];
    133     birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];
    134     birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];
    135     birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];
    136     NSDate *dateBirtday = [NSDate dateFromString:birtday];
    137     NSDate *today = [NSDate dateFromStringWithoutTime:[[NSDate date] strDate]];
    138     NSDate *pointDate = [today dateByAddingTimeInterval:interval];
    139     
    140     //tempDate为number后的日期
    141     NSDate *tempDate = [pointDate dateAddNumber:-number withDateType:dateType];  //临界日期
    142     if ([dateBirtday earlierDate:tempDate] == dateBirtday) {  //如果生日+指定天数大雨tempdate,则通过
    143         return YES;
    144     } else {
    145         return NO;
    146     }
    147 }
    148 
    149 //验证身份证加上指定天数是否小于指定number的类型
    150 + (BOOL)verifyIDCardLessThanPointDate:(NSString *)card withNumber:(NSInteger)number withAddTimeInterval:(NSTimeInterval)interval withDateType:(DateType)dateType
    151 {
    152     NSString *birtday = [VerifyRegexTool getIDCardBirthday:card];   //****年**月**日
    153     //转换为****-**-**
    154     birtday = [birtday stringByReplacingOccurrencesOfString:@"年" withString:@"-"];
    155     birtday = [birtday stringByReplacingOccurrencesOfString:@"月" withString:@"-"];
    156     birtday = [birtday stringByReplacingOccurrencesOfString:@"日" withString:@""];
    157     birtday = [NSString stringWithFormat:@"%@ 00:00",birtday];
    158     NSDate *dateBirtday = [NSDate dateFromString:birtday];
    159     NSDate *today = [NSDate dateFromStringWithoutTime:[[NSDate date] strDate]];
    160     NSDate *pointDate = [today dateByAddingTimeInterval:interval];
    161 
    162     //tempDate为number后的日期
    163     NSDate *tempDate = [pointDate dateAddNumber:-number withDateType:dateType];  //临界日期
    164     if ([tempDate earlierDate:dateBirtday] == tempDate) {  //如果生日+指定天数小于tempdate,则通过
    165         return YES;
    166     } else {
    167         return NO;
    168     }
    169 }
    170 
    171 //得到身份证的生日****这个方法中不做身份证校验,请确保传入的是正确身份证
    172 + (NSString *)getIDCardBirthday:(NSString *)card {
    173     card = [card stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    174     if ([card length] != 18) {
    175         return nil;
    176     }
    177     NSString *birthady = [NSString stringWithFormat:@"%@年%@月%@日",[card substringWithRange:NSMakeRange(6,4)], [card substringWithRange:NSMakeRange(10,2)], [card substringWithRange:NSMakeRange(12,2)]];
    178     return birthady;
    179 }
    180 
    181 //得到身份证的性别(1男0女)****这个方法中不做身份证校验,请确保传入的是正确身份证
    182 + (NSInteger)getIDCardSex:(NSString *)card {
    183     card = [card stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    184     NSInteger defaultValue = 0;
    185     if ([card length] != 18) {
    186         return defaultValue;
    187     }
    188     NSInteger number = [[card substringWithRange:NSMakeRange(16,1)] integerValue];
    189     if (number % 2 == 0) {  //偶数为女
    190         return 0;
    191     } else {
    192         return 1;
    193     }
    194 }
    195 
    196 @end
    复制代码

    身份证校验调用示例:

    1    if (![VerifyRegexTool verifyIDCardNumber:self.IdentityCardNOTextfield.text]) {   //验证身份证是否真实
    2         [self showMessageHUD:@"请输入正确的身份证号码!" withTimeInterval:kShowMessageTime];
    3         return;
    4     }
     
  • 相关阅读:
    【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理
    【bzoj4832】[Lydsy1704月赛]抵制克苏恩 期望dp
    【bzoj3796】Mushroom追妹纸 hash/sa+kmp+二分
    【bzoj3309】DZY Loves Math 莫比乌斯反演+线性筛
    【bzoj2813】 奇妙的Fibonacci数列 线性筛
    面向对象实现简单的学生课程选择
    小案例--面向对象中实现分页
    初识面向对象四(装饰器/反射)
    python小技巧--控制台输出带颜色的文字方法
    初识面向对象三(经典类/多态/鸭子类型/初识封装)
  • 原文地址:https://www.cnblogs.com/yu0806/p/4279887.html
Copyright © 2011-2022 走看看