博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【NumberValidators】大陆身份证验证
阅读量:5279 次
发布时间:2019-06-14

本文共 6114 字,大约阅读时间需要 20 分钟。

需要说明的是这里的大陆身份证识别并不是公安局联网的识别,而是按国标GB 11643进行的验证,所以其验证结果只能说符合国标规范,但不能保证该身份证一定真实存在,如果你实际需求是希望身份证一定真实存在,那么你可以在通过此类库初步验证后,再调用第三方(或牛逼的可以直连公安,毕竟所有的第三方其数据来源必定是公安局)以降低调用成本(公安调用一次两块钱,还不是有钱就能调用!!!)

转到正题,在NumberValidators中,大陆身份证相关的代码均在NumberValidators.IdentityCards下,具体的验证实现为:ID18Validator(第二代身份证,长度为18),ID15Validator(第一代身份证,长度为15),而IDValidatorHelper则为所有实现了IIDValidator(身份证识别接口)且完全按照 ID{Length}Validator 格式命名的身份证识别自动适配静态类(Length为证件号码长度),除基础的验证外,还提供了TryPromotion方法(一代身份证升位成二代身份证)

IIDValidator(身份证识别接口)定义如下

///     /// 所有号码验证类均需实现的基础接口定义    ///     /// 
public interface IValidator
where T : ValidationResult, new() { ///
/// 随机生成一个符合规则的号码 /// ///
string GenerateRandomNumber(); ///
/// 验证号码是否正确 /// ///
///
T Validate(string number); } ///
/// 身份证验证接口 /// public interface IIDValidator : IValidator
{ ///
/// 用于验证的字典数据 /// IValidationDictionary
Dictionary { get; set; } ///
/// 生成身份证号码 /// ///
行政区划编号 ///
出生日期 ///
顺序号 ///
string GenerateID(int areaNumber, DateTime birthDay, int sequenceNumber); ///
/// 验证身份证是否正确 /// ///
待验证的证件号码 ///
允许最小年份,默认0 ///
验证区域级别,默认AreaValidLimit.Province ///
是否忽略校验位验证,默认false ///
验证结果
IDValidationResult Validate(string idNumber, ushort minYear = 0, AreaValidLimit validLimit = AreaValidLimit.Province, bool ignoreCheckBit = false); }  

验证结果IDValidationResult定义如下

///     /// 号码验证结果类    ///     public class ValidationResult    {        ///         /// 验证结果是否通过        ///         public bool IsValid { get; internal set; } = true;        ///         /// 如果验证不通过,这里包含验证失败的原因        ///         public IList
Errors { get; internal set; } = new List
(); ///
/// 当前验证的号码 /// public string Number { get; internal set; } ///
/// 添加错误信息 /// ///
///
internal void AddErrorMessage(string errorMsg, params object[] parameters) { if (parameters != null && parameters.Length > 0) { errorMsg = string.Format(errorMsg, parameters); } this.Errors.Add(errorMsg); this.IsValid = false; } } ///
/// 身份证验证结果类 /// public class IDValidationResult : ValidationResult { ///
/// 身份证号码长度 /// public IDLength IDLength { get; internal set; } ///
/// 身份证上的出生日期 /// public DateTime Birthday { get; internal set; } ///
/// 性别 /// public Gender Gender { get; internal set; } ///
/// 行政区划编码 /// public int AreaNumber { get; internal set; } ///
/// 身份证颁发行政区域(识别出Depth最深的区域),可通过FullName来获取完整的区域名 /// public Area RecognizableArea { get; internal set; } ///
/// 出生登记顺序号 /// public int Sequence { get; internal set; } ///
/// 身份证校验码 /// public char CheckBit { get; internal set; } }

可以根据 IsValid 属性来判断是否验证通过(true/false),如果验证失败,Errors 属性则包含了验证失败的原因,具体的错误原因列表如下

///         /// 身份证号码为空        ///         public const string Empty = "身份证号码为空";        ///         /// 错误的身份证号码        ///         public const string Error = "错误的身份证号码";        ///         /// 无效的出生日期        ///         public const string InvalidBirthday = "无效的出生日期";        ///         /// 出生日期超出允许的年份范围        ///         public const string BirthdayYearOutOfRange = "出生日期超出允许的年份范围{0} ~ {1}";        ///         /// 行政区划识别失败        ///         public const string InvalidArea = "行政区划识别失败";        ///         /// 行政区划识别度不足        ///         public const string AreaLimitOutOfRange = "行政区划识别度低于识别级别 {0}";        ///         /// 错误的校验码        ///         public const string InvalidCheckBit = "错误的校验码";        ///         /// 无效实现        ///         public const string InvalidImplement = "未能找到或无效的 {0} 位身份证实现";        ///         /// 长度错误        ///         public const string LengthOutOfRange = "身份证号码非 {0} 位";

而验证通过时,你可以通过通过其它属性来获取一些你可能感兴趣的信息,比如 Birthday(出生日期)、Gender(性别)、RecognizableArea(识别出的完整区域,你可以通过其FullName获取完整的行政区域名称,比如  上海市市辖区徐汇区)等等……

在身份证识别中,最困难的地方在于行政区划数据整理,而早期的行政区划数据就目前个人而言完全无法获取,所以目前提供用于验证的行政区划数据是基于GBT2260的2013版本,有兴趣的可以去查阅(很遗憾,目前该部分已不再开放,直接返回无权限了,之所以这里还附上地址,只能说可能以后该部分还会开放吧),一代身份证登记时用的是1984年的版本,而在其之后到现在为止,每年都会有行政区域发生调整,所以如果字典数据不全,用目前默认提供的2013版本字典的话,那么要想保证验证的准确性,那么只能判断到行政省的级别(目前还没出现过省级行政区划的变化调整),当然假设也许有人可以弄到所有的行政区划字典(废弃的行政区划编号不会再纳入使用,所以可以保证行政区划编号永久唯一),或者你希望验证的身份证仅属于某些行政区域,那么可以将新的字典赋给 IIDValidator 的 Dictionary 属性来达到全区域验证或特定区域验证的效果。

上面啰嗦了那么多都还没到怎么使用,其实验证非常简单,就一个Validate方法,如果你仅需要验证二代18位身份证的话,那么你可以只使用 ID18Validator,同理如果你只需要验证一代15位身份证也只需要使用ID15Validator(一般不可能会有这种情况,毕竟目前为止一代身份证基本都不被认可,且还在有效期内的应该也为数不多了),当然为了方便使用,你也可以直接使用IDValidatorHelper来进行一个简单的快速调用(这里需要说明的是反射创建的具体验证实例是会被缓存在内存中的,所以这里性能问题基本可以忽略,但这时你就不能通过字典赋值方式来完善或调整验证结果),所以你可以通过以下几种方式进行验证

string id = "32021919900101003X";            var valid = new ID15Validator().Validate(id);            valid = new ID18Validator()            {                //按需对Dictionary赋值            }.Validate(id);            valid = IDValidatorHelper.Validate(id);

注意这里的代码并没使用可选参数,你可以按需传递相关参数,然后除了上面的验证,你还可以通过GenerateRandomNumber或GenerateID生成身份证,需要注意的是IDValidatorHelper并不提供生成身份证的功能,所以这里必须通过ID18Validator或ID15Validator来生成身份证,与GenerateRandomNumber不同,GenerateID方法支持直接传入行政区划编号,且验证规则为10~999999内的数字,需要注意的是此时该行政区划编号可以不在行政区划字典范围内,即此时不会去验证该编号是否在字典中存在,而GenerateRandomNumber是随机从行政区划字典中取一个区县级区域,简单的代码如下

var no = new ID15Validator().GenerateRandomNumber();            no = new ID18Validator().GenerateID(3202, new DateTime(2000, 1, 1), 1);

  如果你在实际使用中有发现问题或Bug,可以在此处回复或至git上建立Issue。

转载于:https://www.cnblogs.com/starfd/p/9046470.html

你可能感兴趣的文章
字符串方法title()、istitle()
查看>>
yield语句
查看>>
查看linux系统中占用cpu最高的语句
查看>>
[洛谷P1738]洛谷的文件夹
查看>>
ubuntu server设置时区和更新时间
查看>>
【京东咚咚架构演进】-- 好文收藏
查看>>
【HTML】网页中如何让DIV在网页滚动到特定位置时出现
查看>>
文件序列化
查看>>
jQuery之end()和pushStack()
查看>>
Bootstrap--响应式导航条布局
查看>>
Learning Python 009 dict(字典)和 set
查看>>
JavaScript中随着鼠标拖拽而移动的块
查看>>
HDU 1021 一道水题
查看>>
The operation couldn’t be completed. (LaunchServicesError error 0.)
查看>>
php每天一题:strlen()与mb_strlen()的作用分别是什么
查看>>
工作中收集JSCRIPT代码之(下拉框篇)
查看>>
《转载》POI导出excel日期格式
查看>>
code异常处理
查看>>
git - 搭建最简单的git server
查看>>
会话控制
查看>>