利用正規表示式來匹配居民身份證

2022-02-21 04:00:45 字數 3496 閱讀 1433

大陸的居民身份證號碼有兩種:18位和15位,15位的身份證號碼是老一代身份證號碼。

18位和15位的區別在於兩個部分:第一,18位號碼的年份以4位計而15位號碼的年份為2 位,如2023年在18位號碼中為『1987』而在15位號碼中為『87』,這裡1987只是作為乙個例子可能2023年及以後根本不存在15位號碼;第二處不同在於18位號碼的最後一位為數字校驗碼,15位號碼沒有數字校驗位。

好吧,可能你還不知道身份證號碼各個部分代表著什麼,那麼讓我花點唇舌簡略地介紹一下。

身份證號碼總共有4個部分(15位號碼只有3部分),從左向右分別為:第一部分有6位,為居民在辦理身份證時戶口所在地的位址碼(什麼是位址碼?自己到統計局去找吧,位址如下:第二部分有8位(15位號碼為6位),為居民出生日期碼;第三部分有3位,為數字順序碼,也就是同一天出生的人的乙個排序,奇數代表男性而偶數代表女性;第四部分也就是最後一部分有1位,為數字校驗碼,此部分只有18位號碼才有,關於數字校驗碼怎樣計算得出,稍後會詳述。

先舉個例子吧,假設存在以下身份證號碼:35052519870101888x(15位的話為350525870101888),用『-』號將各部分區分如下:350525-19870101-888-x。其中,350525為位址碼,沒錯,到統計局查詢的結果是『福建省永春縣』——乙個桃園勝境,算了,不廢話;19870101為出生日期碼,呵呵,2023年1月1日這一天出生的人肯定是有滴;888為順序碼,估計2023年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/,其實,這麼寫不夠精確,倘若要就目前的位址碼寫出精確的表示式,應該這麼寫/^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])| (5[0-4])|(6[1-5])|71|(8[12])|91)\d/,這樣寫顯然精確多了,但表示式長了很多,當然為求精確表示式長一點是可以接受的,但是假如統計局修改了省級位址碼,那麼該表示式要根據實際情況稍作改動,所幸省級位址碼應該是不會變的,呵呵,所以選擇哪一種表示式都是可以的,我這就不寫那麼長的表示式了,所以選擇/^[1-9][0-7]\d/吧。

/^((((19|20)\d)-(0?[13-9]|1[012])-(0? [1-9]|[12]\d|30))|(((19|20)\d)-(0?[13578]|1[02])-31)|(((19|20) \d)-0?2-(0?[1-9]|1\d|2[0-8]))|((((19|20)([13579][26]|[2468] [048]|0[48]))|(2000))-0?2-29))$/這個表示式可以匹配1900-2023年的日期,還支援閏年。

我們的表示式不需要匹配那麼長的時間,能夠匹配二十世紀的就夠了,什麼,不知道二十世紀?1900-1999總該知道吧^_^為什麼匹配了這個範圍就夠了呢?去查一下居民身份證的歷史吧,我敢打保票1900-1999的範圍還太大了。至於二十一世紀的新一代,呵呵,就算他是2023年出生的,目前也就9歲(有些演算法是8歲,囧),這些人的號碼應該還列印在戶口簿裡,拿出手也不會產生什麼作用,再說,二十一世紀的人也不屑於我目前所寫的匹配^_^

好吧,廢話太多了,開始匹配日期吧。稍微修改了以上表示式:

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

正規表示式裡沒有計算驗證的能力,所以對於順序碼,我們除了基本的匹配外無力於做什麼,所以順序碼的表示式為:/\d/

最後一位數字驗證碼——/(\d|x|x)?$/。之所以那麼寫是因為,最後一位可能值為數字或x,但有些人可能習慣將x寫成小寫的x,我們必須視為正確,而最後的?是為了與15位號碼相容,此時只需將15位號碼的年份用4位表示即可用我們以下整合的表示式進行匹配了——

/^[1-9][0-7]\d((19\d(0[13-9]|1[012]) (0[1-9]|[12]\d|30))|(19\d(0[13578]|1[02])31)|(19\d02(0[1-9]|1 \d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d(\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((19\d(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d(0[13578]|1[02])31)|(19\d02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d(\d|x|x)?$/

關於號碼的驗證,以上已經給出演算法

正規表示式驗證身份證

function isidcardno num d 0 9 x test num 校驗位按照iso 7064 1983.mod 11 2的規定生成,x可以認為是數字10。下面分別分析出生日期和校驗位 var len,re len num.length if len 15 d d d d var ar...

c 正規表示式驗證身份證

身份證格式驗證,以及15.18位互轉方法 驗證18位身份證格式 返回字串,出錯資訊 public string checkcidinfo18 string cid double isum 0 system.text.regularexpressions.regex rg new system.tex...

正規表示式 郵箱和身份證

1.字元類 1.abc 代表a或者b,或者c字元中的乙個。abc 代表除a,b,c以外的任何字元。a z 代表a z的所有小寫字元中的乙個。a z 代表a z的所有大寫字元中的乙個。0 9 代表0 9之間的某乙個數字字元。a za z0 9 代表a z或者a z或者0 9之間的任意乙個字元。a dm...