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

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

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

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

验证结果IDValidationResult定义如下

    /// <summary>
/// 号码验证结果类
/// </summary>
public class ValidationResult
{
/// <summary>
/// 验证结果是否通过
/// </summary>
public bool IsValid { get; internal set; } = true;
/// <summary>
/// 如果验证不通过,这里包含验证失败的原因
/// </summary>
public IList<string> Errors { get; internal set; } = new List<string>();
/// <summary>
/// 当前验证的号码
/// </summary>
public string Number { get; internal set; } /// <summary>
/// 添加错误信息
/// </summary>
/// <param name="errorMsg"></param>
/// <param name="parameters"></param>
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;
}
} /// <summary>
/// 身份证验证结果类
/// </summary>
public class IDValidationResult : ValidationResult
{
/// <summary>
/// 身份证号码长度
/// </summary>
public IDLength IDLength { get; internal set; }
/// <summary>
/// 身份证上的出生日期
/// </summary>
public DateTime Birthday { get; internal set; }
/// <summary>
/// 性别
/// </summary>
public Gender Gender { get; internal set; }
/// <summary>
/// 行政区划编码
/// </summary>
public int AreaNumber { get; internal set; }
/// <summary>
/// 身份证颁发行政区域(识别出Depth最深的区域),可通过FullName来获取完整的区域名
/// </summary>
public Area RecognizableArea { get; internal set; }
/// <summary>
/// 出生登记顺序号
/// </summary>
public int Sequence { get; internal set; }
/// <summary>
/// 身份证校验码
/// </summary>
public char CheckBit { get; internal set; }
}

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

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

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

在身份证识别中,最困难的地方在于行政区划数据整理,而早期的行政区划数据就目前个人而言完全无法获取,所以目前提供用于验证的行政区划数据是基于GBT2260的2013版本,有兴趣的可以去http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/查阅(很遗憾,目前该部分已不再开放,直接返回无权限了,之所以这里还附上地址,只能说可能以后该部分还会开放吧),一代身份证登记时用的是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。

【NumberValidators】大陆身份证验证的更多相关文章

  1. 身份证验证JS代码

    身份证验证JS程序function checkidcardfun(code) { var city = {11: "北京", 12: "天津", 13: &qu ...

  2. java身份证验证

    import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; impor ...

  3. jQuery身份证验证插件

    jQuery身份证验证插件 /*! * jQuery isIDCard Plugin v1.0.0 * http://www.cnblogs.com/cssfirefly/p/5629561.html ...

  4. java对身份证验证及正则表达式解析

    原文地址:http://www.cnblogs.com/zhongshengzhen/ java对身份证验证及正则表达式解析 package service; import java.text.Par ...

  5. Jsp注册页面身份证验证

    <!--身份证验证 --><script type="text/javascript">function isCardNo(Idcardnumber) { ...

  6. C#实现中国身份证验证问题

    C#中国身份证验证,包括省份验证和校验码验证,符合GB11643-1999标准...   今天写的 C#中国身份证验证,包括省份验证和校验码验证,符合GB11643-1999标准... 理论部分: 1 ...

  7. Java正则表达式实现港、澳、台身份证验证

    最近由于业务的要求,需要进行港.澳.台人员身份证验证,现在直接上代码,经供参考学习,也为自己积累一些工具类: package com.qiu.validate; public class regexV ...

  8. js邮箱验证,身份证验证,正则表达式

    邮箱验证: html部分: 邮箱验证:<input type="text" id="mail" value="" / onkeyup= ...

  9. Java基础之身份证验证

    //简约版package test; import java.util.Scanner; public class ID { /** * 匹配算法 : 1) 得到17位身份证号码与下面给出的17位 2 ...

随机推荐

  1. unity UGUI实现类似NGUI切换Sprite的方式

    很多都是使用NGUI的习惯,因为在NGUI中所有图片都打包在一个图集中,通过更改SpriteName就可以更改图片,so,为了方便调用UGUI的sprite,我们也同样需要为其创建一个asset文件. ...

  2. Django访问量和页面点击数统计

    http://blog.csdn.net/pipisorry/article/details/47396311 下面是在模板中做一个简单的页面点击数统计.model阅读量统计.用户访问量统计的方法 简 ...

  3. 【面试笔试算法】Program 4 : Best Compression Algorithms(网易游戏笔试题)

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 易信是由网易和电信联合开发的一款即时通讯软件.除了语音聊天,免费电话等新功能以外,传统的文字信息聊天功能也得以保留,因此每 ...

  4. GROUP BY,WHERE,HAVING间的区别和用法

    having子句与where都是过滤语句. where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行 ...

  5. Android绘图机制(四)——使用HelloCharts开源框架搭建一系列炫酷图表,柱形图,折线图,饼状图和动画特效,抽丝剥茧带你认识图表之美

    Android绘图机制(四)--使用HelloCharts开源框架搭建一系列炫酷图表,柱形图,折线图,饼状图和动画特效,抽丝剥茧带你认识图表之美 这里为什么不继续把自定义View写下去呢,因为最近项目 ...

  6. Mac OS 终端常用命令基础

    基础概念 OS X 采用的Unix文件系统,所有文件都挂在跟目录" /" 下面,所以不在要有Windows 下的盘符概念.比如什么"C:"你在桌面上看到的硬盘都 ...

  7. 面试之路(7)-BAT面试题之计算机的三大原则

    1.计算机是执行输入.运算.输出的机器 计 算 机 的 硬 件 由 大 量 的 IC(Integrated Circuit,集成电路)组成.每块 IC 上都带有许多引脚.这些引脚有的用于输入,有的用于 ...

  8. LeetCode(53)-Binary Tree Paths

    题目: Given a binary tree, return all root-to-leaf paths. For example, given the following binary tree ...

  9. 关于ARC的介绍和ARC与MRC混编解决

    1. ARC & MRC 混合开发 在项目开发中,遇到使用MRC开发的第三方库怎么办? 例如:ASI 1> 尝试使用Xcode的转换工具(失败率比较高) 2> 在编译选项中,为MR ...

  10. javascript语言扩展:可迭代对象(1)

    在ECMAScript中我们知道可以通过for in语句进行对象属性的遍历,当然这些属性不包括继承而来的属性: var ary = [1,2,3,"aa",4]; for(i in ...