zoukankan      html  css  js  c++  java
  • 利用正则表达式来匹配居民身份证

    大陆的居民身份证号码有两种:18位和15位,15位的身份证号码是老一代身份证号码。

    18位和15位的区别在于两个部分:第一,18位号码的年份以4位计而15位号码的年份为2 位,如1987年在18位号码中为‘1987’而在15位号码中为‘87’,这里1987只是作为一个例子可能1987年及以后根本不存在15位号码;第二处不同在于18位号码的最后一位为数字校验码,15位号码没有数字校验位。

    好吧,可能你还不知道身份证号码各个部分代表着什么,那么让我花点唇舌简略地介绍一下。

    身份证号码总共有4个部分(15位号码只有3部分),从左向右分别为:第一部分有6位,为居民在办理身份证时户口所在地的地址码(什么是地址码?自己到统计局去找吧,地址如下:http://www.stats.gov.cn/tjbz/index.htm);第二部分有8位(15位号码为6位),为居民出生日期码;第三部分有3位,为数字顺序码,也就是同一天出生的人的一个排序,奇数代表男性而偶数代表女性;第四部分也就是最后一部分有1位,为数字校验码,此部分只有18位号码才有,关于数字校验码怎样计算得出,稍后会详述。

    先举个例子吧,假设存在以下身份证号码:35052519870101888X(15位的话为350525870101888),用‘-’号将各部分区分如下:350525-19870101-888-X。其中,350525为地址码,没错,到统计局查询的结果是‘福建省永春县’——一个桃园胜境,算了,不废话;19870101为出生日期码,呵呵,1987年1月1日这一天出生的人肯定是有滴;888为顺序码,估计1987年1月1日第888个出生的人应该没有吧,倘若真的有,那真不是人,是神!!呵呵,估计我党也不会给神这个号码,不多说了,再多说可能要人神共怒了……好吧,那么X是什么呢?怎么有些人的身份证号码最后一位会突然冒出一个X呢,是这些人比较特殊吗?答案是:不是的,也算是吧,倘若有一种个位数等于10,这些人也不用在身份证号码的最后一位被不明不白地加上一个X了,究竟是怎么一回事且听我细细道来^_^

    18位居民身份证号码最后一位——数字校验码的计算方法:

    1. 将身份证号码的前17位数分别乘以以下系数:7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2;

    2. 将以上分别相乘得到的结果相加;

    3. 将以上相加的结果除以11,得出余数;

    4. 以上得出的余数可能为0 - 10这11个数中的某一个数字。10是一个另类,因为我们的数字校验位只有1位显然需要一种替换方案,用1位将10换下,于是X派上用场了。注意了,数字校验位并不就是余数!!所得的11个余数:

    0,1,2,3,4,5,6,7,8,9,10 的数字校验位分别为:

    1,0,X,9,8,7,6,5,4,3,2

    PS:通过以上的计算,现在应该非常清楚了,身份证号码的最后一位为X是因为在作校验时所得的余数是2,显然这些号码也没什么特别的吗。需要强调一下的是,X并不是英文字母哦,而是罗马数字X,记住,它不是字母而是数字,但是,呵呵,我们一般用英文大写字母X来表示罗马数字X,囧nz……

    让我花点时间来校验以上的身份证号码:35052519870101888X是否正确吧,先声明倘若证实可用千万别拿去做假证,一切本人概不负责!

    1.前17位分别乘以相应系数:3*7+5*9+0*10+5*5+2*8+5*4+1*2+9*1+8*6+7*3+0*7+1*9+0*10+1*5+8*8+8*4+8*2=333(假如没算错的话^_^)

    2.将以上所得结果333除以11,得出余数:3

    3.呵呵35052519870101888X这个号码不是有效的身份证号码,有效号码应该为350525198701018889

    好了,知道了居民身份证号码各部分的意思后,我们终于可以动手寻求号码验证的解决方案了。

    假设我们的系统并不知道输入号码之人的任何信息(如果系统还要求输入籍贯和出生日期,还可以进一步进行检验真伪喔^_^)

    首先,地址码的前2位是省级的编号,到统计局去查询得知第1位非0,并且目前的范围为 1-9,9是国外的身份证号码。第2位的范围为0-7。统计局一般每一年都会公布一次更新的地址码,但对比多年来的地址码可以看出地址码基本上是不变的(要是变了,现有的身份证号码岂不是都没用了^_^)。我们的地址码的正则表达式可以这样写:/^[1-9][0-7]\d{4}/,其实,这么写不够精确,倘若要就目前的地址码写出精确的表达式,应该这么写/^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])| (5[0-4])|(6[1-5])|71|(8[12])|91)\d{4}/,这样写显然精确多了,但表达式长了很多,当然为求精确表达式长一点是可以接受的,但是假如统计局修改了省级地址码,那么该表达式要根据实际情况稍作改动,所幸省级地址码应该是不会变的,呵呵,所以选择哪一种表达式都是可以的,我这就不写那么长的表达式了,所以选择/^[1-9][0-7]\d{4}/吧。

    接下来就是日期了喔,呵呵,貌似之前写过的日期匹配可以借鉴来用一下,当时的那个表达式如下:

    /^((((19|20)\d{2})-(0?[13-9]|1[012])-(0? [1-9]|[12]\d|30))|(((19|20)\d{2})-(0?[13578]|1[02])-31)|(((19|20) \d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|((((19|20)([13579][26]|[2468] [048]|0[48]))|(2000))-0?2-29))$/这个表达式可以匹配1900-2099年的日期,还支持闰年。

    我们的表达式不需要匹配那么长的时间,能够匹配二十世纪的就够了,什么,不知道二十世纪?1900-1999总该知道吧^_^为什么匹配了这个范围就够了呢?去查一下居民身份证的历史吧,我敢打保票1900-1999的范围还太大了。至于二十一世纪的新一代,呵呵,就算他是2000年出生的,目前也就9岁(有些算法是8岁,囧),这些人的号码应该还打印在户口簿里,拿出手也不会产生什么作用,再说,二十一世纪的人也不屑于我目前所写的匹配^_^

    好吧,废话太多了,开始匹配日期吧。稍微修改了以上表达式:

    /((19\d{2}(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))/

    正则表达式里没有计算验证的能力,所以对于顺序码,我们除了基本的匹配外无力于做什么,所以顺序码的表达式为:/\d{3}/

    最后一位数字验证码——/(\d|X|x)?$/。之所以那么写是因为,最后一位可能值为数字或X,但有些人可能习惯将X写成小写的x,我们必须视为正确,而最后的?是为了与15位号码兼容,此时只需将15位号码的年份用4位表示即可用我们以下整合的表达式进行匹配了——

    /^[1-9][0-7]\d{4}((19\d{2}(0[13-9]|1[012]) (0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1 \d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d{3}(\d|X|x)?$/地址码精确一点的表达式:

    /^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])|(5[0-4])|(6[1-5])|71|(8[12])|91)\d{4}((19\d{2}(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d{3}(\d|X|x)?$/

    关于号码的验证,以上已经给出算法

  • 相关阅读:
    Servlet
    javaBean
    堆排序
    快速排序
    JSP9大内置对象
    include指令与<jsp:include>动作标识
    JSP指令标识
    TreeSet
    使用Docker存储之卷Volume
    Java学习之HttpClient的GET与POST请求
  • 原文地址:https://www.cnblogs.com/qingshan/p/1507234.html
Copyright © 2011-2022 走看看