正則匹配身份證有bug你知道麽?

来源:https://www.cnblogs.com/starryqian/archive/2019/01/15/10272793.html
-Advertisement-
Play Games

在開發中,我們需要驗證用戶的輸入信息,多半採用正則驗證,下麵就是身份證證號的幾種常用的正則表達式: 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] ...


在開發中,我們需要驗證用戶的輸入信息,多半採用正則驗證,下麵就是身份證證號的幾種常用的正則表達式:

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值

 

這就是為什麼我們身份證驗證會出錯,因為我們正則只是匹配了形式,並沒有按照身份證的規則去動態驗證,沒有權重

那麼正確的驗證如下

 1 /**
 2  * @params  idCard  string
 3  * @outParams res
 4  *  status : boolean
 5  *  msg : string
 6  *
 7  */
 8 function checkIdcard(idCard) {
 9   idCard = idCard.toString();
10   var city = {
11     11: "北京",
12     12: "天津",
13     13: "河北",
14     14: "山西",
15     15: "內蒙古",
16     21: "遼寧",
17     22: "吉林",
18     23: "黑龍江 ",
19     31: "上海",
20     32: "江蘇",
21     33: "浙江",
22     34: "安徽",
23     35: "福建",
24     36: "江西",
25     37: "山東",
26     41: "河南",
27     42: "湖北 ",
28     43: "湖南",
29     44: "廣東",
30     45: "廣西",
31     46: "海南",
32     50: "重慶",
33     51: "四川",
34     52: "貴州",
35     53: "雲南",
36     54: "西藏 ",
37     61: "陝西",
38     62: "甘肅",
39     63: "青海",
40     64: "寧夏",
41     65: "新疆",
42     71: "臺灣",
43     81: "香港",
44     82: "澳門",
45     91: "國外 "
46   };
47   var tip = "";
48   var pass = true;
49 
50   if (
51     !idCard ||
52     !/^\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(
53       idCard
54     )
55   ) {
56     tip = "身份證號格式錯誤";
57     pass = false;
58   } else if (!city[idCard.substr(0, 2)]) {
59     tip = "地址編碼錯誤";
60     pass = false;
61   } else {
62     //18位身份證需要驗證最後一位校驗位
63     if (idCard.length == 18) {
64       idCard = idCard.split("");
65       //∑(ai×Wi)(mod 11)
66       //加權因數
67       var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
68       //校驗位
69       var parity = [1, 0, "X", 9, 8, 7, 6, 5, 4, 3, 2];
70       var sum = 0;
71       var ai = 0;
72       var wi = 0;
73       for (var i = 0; i < 17; i++) {
74         ai = idCard[i];
75         wi = factor[i];
76         sum += ai * wi;
77       }
78       var last = parity[sum % 11];
79       if (parity[sum % 11] != idCard[17]) {
80         tip = "校驗位錯誤";
81         pass = false;
82       }
83     }
84   }
85   var obj = {
86     status: pass,
87     msg: tip
88   };
89   if (!pass) {
90     return obj;
91   }
92 
93   return obj;
94 }

寫法註意事項:省區編碼,我們可以寫成數組的形式,但是需要去迴圈操作,會比較消耗性能:如果是數組,新手是這麼寫的

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,
    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.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/


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 node中有一組流api,它們可以像處理網路流一樣處理文件。流api用起來非常方便,本節學習介紹文件處理基礎和流的概念。 目錄 1. 處理文件路徑 處理文件路徑需要用到一個核心模塊(path),path模塊可以規範化、連接、解析路徑,還可以將絕對路徑轉換為相對路徑,提取路徑的組成以及判斷路徑是 ...
  • 學習Vue.js時,Chrome瀏覽器安裝Vue.js devtool能很方便的查看Vue對象、組件、事件等。 本文以Chrome瀏覽器插件Vue.js devtools_3.1.2_0.crx的安裝為例。 步驟: 1、打開Chrome瀏覽器,右上角找到“自定義及控制Google Chrome”圖標 ...
  • 1.JavaScript switch 語句 使用 switch 語句來選擇要執行的多個代碼塊之一。 語法: 工作原理:首先設置表達式 n(通常是一個變數)。隨後表達式的值會與結構中的每個 case 的值做比較。如果存在匹配,則與該 case 關聯的代碼塊會被執行。使用 break 來阻止代碼自動地 ...
  • 如果你不小心給其它盒子設置了z-index屬性顯示在最上層而又沒有將該盒子進行隱藏。 <style> .bottom { position: absolute; width:100px; height:100px; background:pink; cursor:pointer; } .top { ...
  • 彈性盒模型 彈性盒子是css3的一種新佈局模式,由容器(父元素)和項目(子元素)組成。 彈性盒子是一種當頁面需要適應不同的屏幕大小以及設備類型時確保元素擁有恰當的行為的佈局方式。 引入彈性盒模型的目的:提供一種更加有效的方式來對一個容器中的子元素進行排列、對齊和分配空白區間。 設置彈性盒子:disp ...
  • 1. 父傳子 2. 子傳父 3. 兄弟相傳 ...
  • 基本選擇器 1.id選擇器 >根據id來獲取,只有一個。 $( " #id的值 " ) 2.標簽選擇器 >根據標簽的名字獲取,可以有多個。 $( " 標簽的名字 " ) 3.類選擇器 >根據類樣式的名字來獲取,可以有多個。 $( " . 類樣式的名字" ) 複雜選擇器 4.標簽+類樣式選擇器 >$( ...
  • 1). location方式 2). router方式 3). provide/inject方式 App.vue export default { name: 'App', // 提供reload方法 provide: function () { return { reload: this.relo ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...