身份證編碼合法性檢測(基於XML數據)

    中國的居民身份證編碼格式爲:2位一級行政區代碼;2位二級行政區代碼;2位三級行政區代碼;8位出生日期(年月日);3位識別碼;1位校驗碼。其中校驗碼執行的是中華人民共和國國家標準GB11643-1999,即ISO7064:1983.MOD 11-2。
    前6位的行政區劃代碼包含的信息只能存儲於數據文件中。我看到許多例子都使用數據庫或文本文件對其存儲,查詢起來很不方便。而使用Microsoft.XMLDOM則簡單易行:首先將身份證數據轉換爲XML格式,然後通過XPath進尋查詢,體積小,速度快,Client或Server均可執行,也可通過AJAX訪問;而不像數據庫,只能在Server執行。以下是全部JavaScript代碼和XML生成算法的C#代碼。

1、HTML文件:

  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  4. <title>居民身份證編碼合法性檢測(基於客戶端XML數據)</title> 
  5. <style type="text/css"> 
  6. body, table {  
  7.     font-family:宋體;  
  8.     font-size:9pt;  
  9. }  
  10. table, td {  
  11.     border-width:1px;  
  12.     border-style:solid;  
  13.     border-color:#000000;  
  14. }  
  15. td {  
  16.     height:30;  
  17. }  
  18. input {  
  19.     width:200px;  
  20.     height:22px;  
  21. }  
  22. </style> 
  23. <script type="text/javascript" src="CheckChineseID.js"></script> 
  24. <script type="text/javascript"> 
  25. function xmlLoad() {  
  26.     var xmlDoc = null;  
  27.     try {  
  28.         if (window.ActiveXObject) //IE  
  29.             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");  
  30.         else if (document.implementation.createDocument) //Mozilla, Firefox, Opera, etc.  
  31.             xmlDoc = document.implementation.createDocument("", "", null);  
  32.         xmlDoc.async = false;  
  33.         xmlDoc.load("ChineseID.xml");  
  34.         xmlDoc.setProperty("SelectionLanguage", "XPath");  
  35.     }  
  36.     finally {  
  37.         return xmlDoc;  
  38.     }  
  39. }  
  40. var xmlDoc = xmlLoad();  
  41. function show() {  
  42.     if (xmlDoc == null)  
  43.         alert(navigator.appName + "不支持XML對象,程序無法運行!");  
  44.     else {  
  45.         var result = checkId(id.value, xmlDoc);  
  46.         if (typeof result == "string") {  
  47.             t0.innerHTML = result;  
  48.             t0.style.color = "#FF0000";  
  49.             t1.innerHTML = t2.innerHTML = t3.innerHTML = t4.innerHTML = t5.innerHTML = "N/A";  
  50.         }  
  51.         else {  
  52.             t0.innerHTML = "檢測通過!";  
  53.             t0.style.color = "#008000";  
  54.             t1.innerHTML = result[0];  
  55.             t2.innerHTML = result[1];  
  56.             t3.innerHTML = result[2];  
  57.             t4.innerHTML = result[3] + "年" + result[4] + "月" + result[5] + "日【" + result[6] + "歲】";  
  58.             t5.innerHTML = result[7] + "【" + result[8] + "】";  
  59.         }  
  60.         var blink = 0;  
  61.         var blinkId = setInterval(function () {  
  62.             blink % 2 == 0 ? t0.style.backgroundColor = "#FFFFC0" : t0.style.backgroundColor = "#FFFFFF";  
  63.             if (blink++ == 5) clearInterval(blinkId);  
  64.         }, 200);  
  65.     }  
  66. }  
  67. </script> 
  68. </head> 
  69. <body> 
  70. <p align="center"> 
  71. <small><sub>居民</sub></small>身份證編碼合法性檢測(基於客戶端XML數據)<br /><br /> 
  72. 白宇 - 夢遼軟件工作室 - 博訊網絡有限責任公司<br /> 
  73. Baiyu - Mengliao Software Studio - Bosun Network Co., Ltd.<br /> 
  74. 2012.03.02</p> 
  75. <center> 
  76. <table cellpadding="5" cellspacing="0" width="320"> 
  77.     <tr> 
  78.         <td width="100">身份證號碼</td> 
  79.         <td align="center"> 
  80.             <input type="text" maxlength="18" id="id" value="請輸入18位身份證號碼" style="color:#CCCCCC" 
  81.                 onfocus="if(this.value=='請輸入18位身份證號碼'){this.value='';this.style.color='#000000';}" 
  82.                 onblur="if(this.value==''){this.value='請輸入18位身份證號碼';this.style.color='#CCCCCC';}" 
  83.                 ondblclick="clipboardData.setData('Text','150722201203020010');alert('示例:150722201203020010\n\n該示例已複製到剪貼板!');" 
  84.                 onkeypress="if(event.keyCode==13) btn.click()" /> 
  85.         </td> 
  86.     </tr> 
  87.     <tr> 
  88.         <td>檢測結果</td> 
  89.         <td id="t0">N/A</td> 
  90.     </tr> 
  91.     <tr> 
  92.         <td>一級行政區</td> 
  93.         <td id="t1">N/A</td> 
  94.     </tr> 
  95.     <tr> 
  96.         <td>二級行政區</td> 
  97.         <td id="t2">N/A</td> 
  98.     </tr> 
  99.     <tr> 
  100.         <td>三級行政區</td> 
  101.         <td id="t3">N/A</td> 
  102.     </tr> 
  103.     <tr> 
  104.         <td>出生日期</td> 
  105.         <td id="t4">N/A</td> 
  106.     </tr> 
  107.     <tr> 
  108.         <td>識別碼</td> 
  109.         <td id="t5">N/A</td> 
  110.     </tr> 
  111.     <tr> 
  112.         <td colspan="2" align="center"><input type="button" id="btn" value="檢測" onclick="show()" /></td> 
  113.     </tr> 
  114. </table> 
  115. </center> 
  116. </body> 
  117. </html> 

2、JavaScript文件:

  1. function checkId(id, xmlDoc) {  
  2.     var result = new Array();  
  3.     var months = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);  
  4.     if (!id.match(/^\d{17}[\d|x]$/i))  
  5.         return "【格式】檢測錯誤!";  
  6.     var t = xmlDoc.selectNodes("/China/Province[Code='" + id.substr(0, 2) + "0000']/Name")  
  7.     if (t[0] == null)  
  8.         return "【一級行政區】檢測錯誤!";  
  9.     else 
  10.         result.push(t[0].text);  
  11.     t = xmlDoc.selectNodes("/China/Province/City[Code='" + id.substr(0, 4) + "00']/Name")  
  12.     if (t[0] == null)  
  13.         return "【二級行政區】檢測錯誤!";  
  14.     else 
  15.         result.push(t[0].text);  
  16.     t = xmlDoc.selectNodes("/China/Province/City/District[Code='" + id.substr(0, 6) + "']/Name")  
  17.     if (t[0] == null)  
  18.         return "【三級行政區】檢測錯誤!";  
  19.     else 
  20.         result.push(t[0].text);  
  21.     var y, m, d, now = new Date();  
  22.     y = parseInt(id.substr(6, 4));  
  23.     m = parseInt(id.substr(10, 2));  
  24.     d = parseInt(id.substr(12, 2));  
  25.     if (new Date(y + 150, m - 1, d) < now || new Date(y, m - 1, d) > now)  
  26.         return "【日期範圍】檢測錯誤!";  
  27.     else 
  28.         result.push(y);  
  29.     if (m < 1 || m > 12)  
  30.         return "【月】檢測錯誤!";  
  31.     else 
  32.         result.push(m);  
  33.     if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)  
  34.         months[1] = 29;  
  35.     if (d < 1 || d > months[m - 1])  
  36.         return "【日】檢測錯誤!";  
  37.     else 
  38.         result.push(d);  
  39.     result.push(now.getFullYear() - y);   
  40.     if (id.substr(14, 3) == 0)  
  41.         return "【識別碼】檢測錯誤!";  
  42.     else {  
  43.         result.push(id.substr(14, 3));  
  44.         result.push(id.substr(14, 3) % 2 == 0 ? "女" : "男");  
  45.     }  
  46.     /*  
  47.     校驗碼Hash算法  
  48.     中華人民共和國國家標準GB11643-1999  
  49.     ISO 7064:1983.MOD 11-2校驗碼算法:  
  50.     1) 十七位數字本體碼加權求和公式  
  51.     S = Sum(Ai * Wi), i = 0, ... , 16 ,先對前17位數字的權求和  
  52.     Ai:表示第i位置上的身份證號碼數字值  
  53.     Wi:表示第i位置上的加權因子  
  54.     Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2  
  55.     Wi也可表示爲:2^(17 - i) % 11  
  56.     2) 計算模  
  57.     Y = mod(S, 11)  
  58.     3) 通過模得到對應的校驗碼V  
  59.     Y:0 1 2 3 4 5 6 7 8 9 10  
  60.     V:1 0 X 9 8 7 6 5 4 3 2  
  61.     V也可表示爲:mod(12 - Y, 11), 如結果爲10,則轉換爲X  
  62.     */ 
  63.     var Y = 0;  
  64.     for (var i = 0; i < 17; i++) {  
  65.         var Ai = parseInt(id.substr(i, 1));  
  66.         var Wi = Math.pow(2, 17 - i) % 11;  
  67.         Y += Ai * Wi;  
  68.     }  
  69.     Y = (12 - Y % 11) % 11;  
  70.     var V = Y == 10 ? "X" : Y.toString();  
  71.     if (V != id.substr(17, 1).toUpperCase())  
  72.         return "【校驗碼】檢測錯誤!" 
  73.     return result;  

3、已經轉換好的“行政區劃XML數據”,下載後將其保存爲ChineseID.xml:

http://mengliao.blog.51cto.com/attachment/201204/876134_1334981976.xml

    這個XML文件是用C#編寫了一個小程序,對統計局的純文本文件進行轉換,使用了LINQ,核心代碼如下:

  1. class Program  
  2. {  
  3.     static void Main()  
  4.     {  
  5.         Console.WriteLine("開始生成XML文件...\n");  
  6.         using (StreamReader sr = new StreamReader("行政區劃代碼.txt"))  
  7.         {  
  8.             int Pid = 0, Cid = 0, Did = 0;  
  9.             XElement xe = new XElement("China");  
  10.             while (!sr.EndOfStream)  
  11.             {  
  12.                 string[] items = sr.ReadLine().Split(',');  
  13.                 if (items[0].Substring(2, 4) == "0000"// 後四位爲0,省區級行政區  
  14.                 {  
  15.                     xe.Add(new XElement("Province",  
  16.                         new XAttribute("P.ID", Pid++),  
  17.                         new XElement("Name", items[1]),  
  18.                         new XElement("Code", items[0])));  
  19.                     Cid = 0; // 文件格式中按置省區、市縣、三級行政區依次排列,故沒開始一個新省區行政區,則市縣行政區ID歸0  
  20.                     Console.Write("生成[{0}]...", items[1]);  
  21.                 }  
  22.                 else if (items[0].Substring(4, 2) == "00"// 否則後兩位爲0,市縣級行政區  
  23.                 {  
  24.                     var query = (from p in xe.Elements()  
  25.                                  where p.Element("Code").Value.Substring(0, 2) == items[0].Substring(0, 2)  
  26.                                  select p).Single();  
  27.                     query.Add(new XElement("City",  
  28.                         new XAttribute("C.ID", Cid++),  
  29.                         new XElement("Name", items[1]),  
  30.                         new XElement("Code", items[0])));  
  31.                     Did = 0; // 文件格式中按置省區、市縣、三級行政區依次排列,故沒開始一個新市縣行政區,則三級行政區ID歸0  
  32.                 }  
  33.                 else // 否則後兩位不爲0,三級行政區  
  34.                 {  
  35.                     // 分兩步執行查詢,提高性能  
  36.                     var query = (from p in xe.Elements() // 獲取所有Province元素  
  37.                                  where p.Element("Code").Value.Substring(0, 2) == items[0].Substring(0, 2)  
  38.                                  from c in p.Elements("City"// 獲取該Province元素下的所有City元素  
  39.                                  where c.Element("Code").Value.Substring(2, 2) == items[0].Substring(2, 2)  
  40.                                  select c).Single();  
  41.                     query.Add(new XElement("District",  
  42.                         new XAttribute("D.ID", Did++),  
  43.                         new XElement("Name", items[1]),  
  44.                         new XElement("Code", items[0])));  
  45.                     Console.Write(".");  
  46.                 }  
  47.             }  
  48.             // 添加註釋,並保存(可以使用XElement直接保存)  
  49.             XDocument xDoc = new XDocument(new XComment("夢遼軟件2012.03生成"),  
  50.                 new XComment("國家統計局截至2011.10.31縣及縣以上行政區劃代碼"));  
  51.             xDoc.Add(xe);  
  52.             xDoc.Save("ChineseID.xml");  
  53.             Console.Write("\n\nXML文件成功生成,按任意鍵退出...");  
  54.             Console.ReadKey();  
  55.         }  
  56.     }  

    以上代碼該有的註釋都有了,就不多解釋了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章