关闭

正则匹配身份证有bug你知道么?

时间: 2019-01-16阅读: 1845标签: 正则

在开发中,我们需要验证用户的输入信息,多半采用正则验证,下面就是身份证证号的几种常用的正则表达式:

var  reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;

var reg= /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$/;

var  reg = /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$/;

但是这些并不能管用,是不是很气人,这是为什么呢?下面我们看一下身份证的规则


身份证查询系统说明:

输入准确的18位身份证号码即可查询身份证号码归属地,年龄,性别,通过身份证号码查询姓名。

输入不合法格式的身份证号码会提示身份证号码错误,本身份证号码查询系统也可作为身份证号码验证。

身份证号码和姓名格式科普:前1-6位为行政区划代码即归属地,第7-14位为出生年月日,第15-17位为顺序代码,在同一个地区出生同一个出生的人通过顺序号码区分,第17位奇数表示男性,偶数表示女性,第18位为校验码,用于校验身份证号码是否合法

 

很显然我们正则验证出错的原因就是第18位,用于身份证号是否合法验证的校验

这是为什么呢?是不是很诡异?按照道理讲,不应该不符合就是false?但是返回的都是true;

因为是这样的,我们使用的正则表达式 reg.test(''),当我们使用test其实就是通过我们写的正则表达式去动态匹配我们输入的字符串是否符合我们表达式的要求,如果符合就会返回Boolean值

 

这就是为什么我们身份证验证会出错,因为我们正则只是匹配了形式,并没有按照身份证的规则去动态验证,没有权重

那么正确的验证如下

/**
 * @params  idCard  string
 * @outParams res
 *  status : boolean
 *  msg : string
 *
 */
function checkIdcard(idCard) {
  idCard = idCard.toString();
  var city = {
    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: "澳门",
    91: "国外 "
  };
  var tip = "";
  var pass = true;

  if (
    !idCard ||
    !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i.test(
      idCard
    )
  ) {
    tip = "身份证号格式错误";
    pass = false;
  } else if (!city[idCard.substr(0, 2)]) {
    tip = "地址编码错误";
    pass = false;
  } else {
    //18位身份证需要验证最后一位校验位
    if (idCard.length == 18) {
      idCard = idCard.split("");
      //∑(ai×Wi)(mod 11)
      //加权因子
      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 sum = 0;
      var ai = 0;
      var wi = 0;
      for (var i = 0; i < 17; i++) {
        ai = idCard[i];
        wi = factor[i];
        sum += ai * wi;
      }
      var last = parity[sum % 11];
      if (parity[sum % 11] != idCard[17]) {
        tip = "校验位错误";
        pass = false;
      }
    }
  }
  var obj = {
    status: pass,
    msg: tip
  };
  if (!pass) {
    return obj;
  }

  return obj;
}


写法注意事项:省区编码,我们可以写成数组的形式,但是需要去循环操作,会比较消耗性能:如果是数组,新手是这么写的  

function checkIdcard(idCard) {
  idCard = idCard.toString();
  var city = [
    11,
    12,
    13,
    14,
    15,
    21,
    22,
    23,
    31,
    33,
    34,
    35,
    36,
    37,
    41,
    42,
    43,
    44,
    45,
    46,
    50,
    51,
    52,
    54,
    61,
    62,
    63,
    64,
    65,
    71,
    81,
    91
  ];
  var tip = "";
  var pass = true;
  var Flag = true;
  for(var i=0;i<city.length;i++){
    if (city[i] == idCard.substr(0, 2)) Falg= false;
  }
  if (
    !idCard ||
    !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i.test(
      idCard
    )
  ) {
    tip = "身份证号格式错误";
    pass = false;
  } else if (!Flag) {
           tip = "地址编码错误";
           pass = false;
         } else {
           //18位身份证需要验证最后一位校验位
           if (idCard.length == 18) {
             idCard = idCard.split("");
             //∑(ai×Wi)(mod 11)
             //加权因子
             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 sum = 0;
             var ai = 0;
             var wi = 0;
             for (var i = 0; i < 17; i++) {
               ai = idCard[i];
               wi = factor[i];
               sum += ai * wi;
             }
             var last = parity[sum % 11];
             if (parity[sum % 11] != idCard[17]) {
               tip = "校验位错误";
               pass = false;
             }
           }
         }
  var obj = {
    status: pass,
    msg: tip
  };
  if (!pass) {
    return obj;
  }
 
  return obj;
}


优化上面的代码 

/**
 * @params  idCard  string
 * @outParams res
 *  status : boolean
 *  msg : string
 *
 */
function checkIdcard(idCard) {
  idCard = idCard.toString();
  var city = [
    11,
    12,
    13,
    14,
    15,
    21,
    22,
    23,
    31,
    33,
    34,
    35,
    36,
    37,
    41,
    42,
    43,
    44,
    45,
    46,
    50,
    51,
    52,
    54,
    61,
    62,
    63,
    64,
    65,
    71,
    81,
  ];
  var tip = "";
  var pass = true;

  if (
    !idCard ||
    !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i.test(
      idCard
    )
  ) {
    tip = "身份证号格式错误";
    pass = false;
  } else if (city.indexOf(idCard.substr(0, 2)) < 0) {
    tip = "地址编码错误";
    pass = false;
  } else {
    //18位身份证需要验证最后一位校验位
    if (idCard.length == 18) {
      idCard = idCard.split("");
      //∑(ai×Wi)(mod 11)
      //加权因子
      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 sum = 0;
      var ai = 0;
      var wi = 0;
      for (var i = 0; i < 17; i++) {
        ai = idCard[i];
        wi = factor[i];
        sum += ai * wi;
      }
      var last = parity[sum % 11];
      if (parity[sum % 11] != idCard[17]) {
        tip = "校验位错误";
        pass = false;
      }
    }
  }
  var obj = {
    status: pass,
    msg: tip
  };
  if (!pass) {
    return obj;
  }

  return obj;
}

注意一下写法,尽量减少循环的操作,推荐使用第一种和第三种用法;如果你是es6用户,那么建议var 修改成 let 

最后基于模块的思想,建议搭建可以在实际开发中,把验证的方法统一一个对象去处理,

然后哪里需要哪里引入。

参考博文:https://blog.csdn.net/a632202838/article/details/44827427
在线身份查询:http://sfz.diqibu.com/
来自:https://www.cnblogs.com/starryqian/archive/2019/01/15/10272793.html


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/1827

关闭

JS 正则表达式^$详解,^与$同时写表示什么意思?

对于初学正则的同学来说,^$这两个看似简单的字符却在使用中总让匹配结果超出我们的预期,^什么时候表示行首什么时候表示反义?^ $两个一起写表示什么含义?今天我们就来详细聊聊这两个字符。

精准准确的统一社会信用代码正则(js)

统一代码为18位,统一代码由十八位的数字或大写英文字母(不适用I、O、Z、S、V)组成,由五个部分组成:第一部分(第1位)为登记管理部门代码,9表示工商部门;(数字或大写英文字母)

常用JavaScript正则表达式整理

在表单验证中,正则表达式书写起来特别繁琐,本文整理了15个常用的JavaScript正则表达式,其中包括用户名、密码强度、整数、数字、电子邮件地址(Email)、手机号码、身份证号、URL地址、 IPv4地址

一次性搞懂JavaScript正则表达式之引擎

我们说正则表达式是语言无关的,是因为驱动正则表达式的引擎是相似的。鉴于正则表达式是一种古老的语法,正则匹配的性能不是很高的么?匹配到就是匹配到,没匹配到就是没匹配到,怎么会在里面走不出来了呢?

ES6正则的扩展

参数为字符串, 那么第二个参数表示正则表达式的修饰符,如下:字符串对象共有4个方法,可以使用正则表达式: match()、 replace()、search() 和 split()。

JS常用正则表达式备忘录

正则表达式或regex用于匹配字符串的各个部分 下面是我创建正则表达式的备忘单。匹配正则使用 .test() 方法,匹配多个模式使用操作符号 |,使用i标志表示忽略大小写

从vue模板解析学习正则表达式

最近在看vue的模板解析成render这一块,顺便补一下正则的知识。attribute这段正则很长,他的主要作用是匹配标签里的指令,可以分几个分组来解读

js常用正则表达式验证大全(整理详细且实用)

正则表达式对象用来规范一个规范的表达式,本文讲的是JS正则表达式大全(整理详细且实用),包括校验数字、字符、一些特殊的需求等等

javascript较全常用的表达正则验证,js中采用test()方法

正则表达式是一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。本文整理了JS较全且实用正则表达式。

JS校验身份证号的合法性

前端表单中有身份证号的校验,下边是用JS来校验身份证号的合法性。中国居民身份证号码编码规则、中国居民身份证校验码算法、JS校验身份证合法性。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!