身份证号码的正则表达式及验证详解(Javascript, Regex) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
iFat3
V2EX    Javascript

身份证号码的正则表达式及验证详解(Javascript, Regex)

  •  
  •   iFat3 2018-03-20 19:07:56 +08:00 2911 次点击
    这是一个创建于 2765 天前的主题,其中的信息可能已经有所发展或是发生改变。

    简言

    在做用户实名验证时,常会用到身份证号码的正则表达式及校验方案。本文列举了两种验证方案,大家可以根据自己的项目实际情况,选择适合的方案。

    idcard-check

    身份证号码说明

    居民身份证号码,正确、正式的称谓应该是“公民身份号码”。根据 [中华人民共和国国家标准 GB 11643-1999 ] 中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本体码和一位数字校验码组成。排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

    以北京市朝阳区一女性身份证号码为例,身份证号码所表示的含义如下图所示:

    身份证号码含义解析

    注:该身份证号码来源于国标 [ GB 11643-1999 ] 。

    下面我们就从零开始完成一个完整的身份证号码校验过程。

    方案 1 (简单)

    1.1 分部规则

    我们首先提出方案 1,并分步做如下规则定义:

    1.1.1 地址码规则:

    • 地址码长 6 位
    • 以数字 1-9 开头
    • 后 5 位为 0-9 的数字

    根据以上规则,写出地址码的正则表达式: /^[1-9]\d{5}/

    1.1.2 年份码规则:

    • 年份码长 4 位
    • 以数字 18,19 或 20 开头
    • 剩余两位为 0-9 的数字

    根据以上规则,写出年份码的正则表达式: /(18|19|20)\d{2}/。如果不需要 18 开头的年份,可以去掉 18。

    1.1.3 月份码规则:

    • 月份码长 2 位
    • 第一位数字为 0,第二位数字为 1-9
    • 或者第一位数字为 1,第二位数字为 0-2

    根据以上规则,写出月份码的正则表达式: /((0[1-9])|(1[0-2]))/

    1.1.4 日期码规则:

    • 日期码长 2 位
    • 第一位数字为 0-2,第二位数字为 1-9
    • 或者是 10,20,30,31

    根据以上规则,写出日期码的正则表达式 :/(([0-2][1-9])|10|20|30|31)/

    1.1.5 顺序码规则:

    • 顺序码长 3 位
    • 顺序码是数字

    根据以上规则,写出顺序码的正则表达式 :/\d{3}/

    1.1.6 校验码规则:

    • 校验码长 1 位
    • 可以是数字,字母 x 或字母 X

    根据以上规则,写出校验码的正则表达式 :/[0-9Xx]/

    1.2 方案 1 正则表达式

    综合以上 6 条规则,给出完整的正则表达式及测试程序如下:

    var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; //输出 true console.log(p.test("11010519491231002X")); //输出 false 不能以 0 开头 console.log(p.test("01010519491231002X")); //输出 false 年份不能以 17 开头 console.log(p.test("11010517491231002X")); //输出 false 月份不能为 13 console.log(p.test("11010519491331002X")); //输出 false 日期不能为 32 console.log(p.test("11010519491232002X")); //输出 false 不能以 a 结尾 console.log(p.test("11010519491232002a")); 

    演示代码

    1.3 方案 1 分析

    方案 1 只是做了基本的格式判定,存在三个主要的不足:

    • 地址码判定不够精确。例:我国并不存在 16,26 开头的地区,却可通过验证
    • 日期判定不够精确。例:19490231 也可通过验证,而 2 月并不存在 31 日
    • 校验码是由 17 位本体码计算得出,方案 1 并未校验此码

    方案 2 (全面)

    根据方案 1 的不足,引入方案 2 进而改进方案 1 的不足。

    2.1 省级地址码校验

    华北:北京 11,天津 12,河北 13,山西 14,内蒙古 15

    东北: 辽宁 21,吉林 22,黑龙江 23

    华东: 上海 31,江苏 32,浙江 33,安徽 34,福建 35,江西 36,山东 37

    华中: 河南 41,湖北 42,湖南 43

    华南: 广东 44,广西 45,海南 46

    西南: 四川 51,贵州 52,云南 53,西藏 54,重庆 50

    西北: 陕西 61,甘肃 62,青海 63,宁夏 64,新疆 65

    特别:台湾 71,香港 81,澳门 82

    根据上述地址码做身份证号码的前两位校验,进一步的提高准确率。当前的地址码以 2013 版的行政区划代码 [ GB/T2260 ] 为标准。由于区划代码的历史演变,使得地址码后四位校验变得不太可能。以三胖的身份证号为例,本人号码是 2321 开头,而当前行政区划代码表中并无此代码。因此本文只做前两位省级地址码的校验。

    也有说法表述 91 开头是外国人取得中国身份证号码的前两位编码,但本人并未得到证实。如有持 91 开头身份证或认识马布里的,请帮忙确认相关信息。

    根据以上分析,给出省级地址码校验及测试程序如下:

    var checkProv = function (val) { var pattern = /^[1-9][0-9]/; var provs = {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:"澳门"}; if(pattern.test(val)) { if(provs[val]) { return true; } } return false; } //输出 true,37 是山东 console.log(checkProv(37)); //输出 false,16 不存在 console.log(checkProv(16)); 

    演示代码

    2.2 出生日期码校验

    出生日期码的校验不做解释,直接给出如下函数及测试程序:

    var checkDate = function (val) { var pattern = /^(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)$/; if(pattern.test(val)) { var year = val.substring(0, 4); var mOnth= val.substring(4, 6); var date = val.substring(6, 8); var date2 = new Date(year+"-"+month+"-"+date); if(date2 && date2.getMonth() == (parseInt(month) - 1)) { return true; } } return false; } //输出 true console.log(checkDate("20180212")); //输出 false 2 月没有 31 日 console.log(checkDate("20180231")); 

    演示代码

    2.3 校验码校验

    校验码的计算略复杂,先给出如下公式:

    校验码公式

    其中 ai 表示身份证本体码的第 i 位值,而 Wi 表示第 i 位的加权因子值。

    加权因子表 [表 1 ] :

    | i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | -------- | -------- | ----- |------ |------ |------ |----- |----- |------ | | Wi | 7 | 9 | 10 | 5 | 8 | 4 | 2 | 1 | | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | | 6 | 3 | 7 | 9 | 10 | 5 | 8 | 4 | 2 |

    X 与校验码换算表 [表 2 ]

    | X | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | | ----- | ----- | ----- |---- |---- |---- |--- |--- |---- |---- |---- |---- | | a18 | 1 | 0 | X | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |

    算法过程:

    • 根据身份证主体码(前 17 位)分别与对应的加权因子(表 1 )计算乘积再求和,根据所得结果与 11 取模得到 X 值。
    • 根据 X 值查询表 2,得出 a18 即校验码值。

    校验码计算程序及测试见如下代码:

    var checkCode = function (val) { var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; var factor = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ]; var parity = [ 1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2 ]; var code = val.substring(17); if(p.test(val)) { var sum = 0; for(var i=0;i<17;i++) { sum += val[i]*factor[i]; } if(parity[sum % 11] == code.toUpperCase()) { return true; } } return false; } // 输出 true, 校验码相符 console.log(checkCode("11010519491231002X")); // 输出 false, 校验码不符 console.log(checkCode("110105194912310021")); 

    演示代码

    2.4 方案 2 整体代码

    var checkID = function (val) { if(checkCode(val)) { var date = val.substring(6,14); if(checkDate(date)) { if(checkProv(val.substring(0,2))) { return true; } } } return false; } //输出 true console.log(checkID("11010519491231002X")); //输出 false,校验码不符 console.log(checkID("110105194912310021")); //输出 false,日期码不符 console.log(checkID("110105194902310026")); //输出 false,地区码不符 console.log(checkID("160105194912310029"));

    演示代码

    以上为三胖对身份证号码验证的理解和分析,如有不足请大家予以指正。

    知名物理学家史蒂芬?霍金于 2018 年 3 月 14 日去世,享年 76 岁。一个博学又有趣的人,一路走好!

    世间再无霍金,时间永留简史!

    原文地址

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3088 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 00:29 PVG 08:29 LAX 17:29 JFK 20:29
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86