中国的居民身份证编码格式为: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文件:
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>居民身份证编码合法性检测(基于客户端XML数据)</title>
- <style type="text/css">
- body, table {
- font-family:宋体;
- font-size:9pt;
- }
- table, td {
- border-width:1px;
- border-style:solid;
- border-color:#000000;
- }
- td {
- height:30;
- }
- input {
- width:200px;
- height:22px;
- }
- </style>
- <script type="text/javascript" src="CheckChineseID.js"></script>
- <script type="text/javascript">
- function xmlLoad() {
- var xmlDoc = null;
- try {
- if (window.ActiveXObject) //IE
- xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
- else if (document.implementation.createDocument) //Mozilla, Firefox, Opera, etc.
- xmlDoc = document.implementation.createDocument("", "", null);
- xmlDoc.async = false;
- xmlDoc.load("ChineseID.xml");
- xmlDoc.setProperty("SelectionLanguage", "XPath");
- }
- finally {
- return xmlDoc;
- }
- }
- var xmlDoc = xmlLoad();
- function show() {
- if (xmlDoc == null)
- alert(navigator.appName + "不支持XML对象,程序无法运行!");
- else {
- var result = checkId(id.value, xmlDoc);
- if (typeof result == "string") {
- t0.innerHTML = result;
- t0.style.color = "#FF0000";
- t1.innerHTML = t2.innerHTML = t3.innerHTML = t4.innerHTML = t5.innerHTML = "N/A";
- }
- else {
- t0.innerHTML = "检测通过!";
- t0.style.color = "#008000";
- t1.innerHTML = result[0];
- t2.innerHTML = result[1];
- t3.innerHTML = result[2];
- t4.innerHTML = result[3] + "年" + result[4] + "月" + result[5] + "日【" + result[6] + "岁】";
- t5.innerHTML = result[7] + "【" + result[8] + "】";
- }
- var blink = 0;
- var blinkId = setInterval(function () {
- blink % 2 == 0 ? t0.style.backgroundColor = "#FFFFC0" : t0.style.backgroundColor = "#FFFFFF";
- if (blink++ == 5) clearInterval(blinkId);
- }, 200);
- }
- }
- </script>
- </head>
- <body>
- <p align="center">
- <small><sub>居民</sub></small>身份证编码合法性检测(基于客户端XML数据)<br /><br />
- 白宇 - 梦辽软件工作室 - 博讯网络有限责任公司<br />
- Baiyu - Mengliao Software Studio - Bosun Network Co., Ltd.<br />
- 2012.03.02</p>
- <center>
- <table cellpadding="5" cellspacing="0" width="320">
- <tr>
- <td width="100">身份证号码</td>
- <td align="center">
- <input type="text" maxlength="18" id="id" value="请输入18位身份证号码" style="color:#CCCCCC"
- onfocus="if(this.value=='请输入18位身份证号码'){this.value='';this.style.color='#000000';}"
- onblur="if(this.value==''){this.value='请输入18位身份证号码';this.style.color='#CCCCCC';}"
- ondblclick="clipboardData.setData('Text','150722201203020010');alert('示例:150722201203020010\n\n该示例已复制到剪贴板!');"
- onkeypress="if(event.keyCode==13) btn.click()" />
- </td>
- </tr>
- <tr>
- <td>检测结果</td>
- <td id="t0">N/A</td>
- </tr>
- <tr>
- <td>一级行政区</td>
- <td id="t1">N/A</td>
- </tr>
- <tr>
- <td>二级行政区</td>
- <td id="t2">N/A</td>
- </tr>
- <tr>
- <td>三级行政区</td>
- <td id="t3">N/A</td>
- </tr>
- <tr>
- <td>出生日期</td>
- <td id="t4">N/A</td>
- </tr>
- <tr>
- <td>识别码</td>
- <td id="t5">N/A</td>
- </tr>
- <tr>
- <td colspan="2" align="center"><input type="button" id="btn" value="检测" onclick="show()" /></td>
- </tr>
- </table>
- </center>
- </body>
- </html>
2、JavaScript文件:
- function checkId(id, xmlDoc) {
- var result = new Array();
- var months = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
- if (!id.match(/^\d{17}[\d|x]$/i))
- return "【格式】检测错误!";
- var t = xmlDoc.selectNodes("/China/Province[Code='" + id.substr(0, 2) + "0000']/Name")
- if (t[0] == null)
- return "【一级行政区】检测错误!";
- else
- result.push(t[0].text);
- t = xmlDoc.selectNodes("/China/Province/City[Code='" + id.substr(0, 4) + "00']/Name")
- if (t[0] == null)
- return "【二级行政区】检测错误!";
- else
- result.push(t[0].text);
- t = xmlDoc.selectNodes("/China/Province/City/District[Code='" + id.substr(0, 6) + "']/Name")
- if (t[0] == null)
- return "【三级行政区】检测错误!";
- else
- result.push(t[0].text);
- var y, m, d, now = new Date();
- y = parseInt(id.substr(6, 4));
- m = parseInt(id.substr(10, 2));
- d = parseInt(id.substr(12, 2));
- if (new Date(y + 150, m - 1, d) < now || new Date(y, m - 1, d) > now)
- return "【日期范围】检测错误!";
- else
- result.push(y);
- if (m < 1 || m > 12)
- return "【月】检测错误!";
- else
- result.push(m);
- if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
- months[1] = 29;
- if (d < 1 || d > months[m - 1])
- return "【日】检测错误!";
- else
- result.push(d);
- result.push(now.getFullYear() - y);
- if (id.substr(14, 3) == 0)
- return "【识别码】检测错误!";
- else {
- result.push(id.substr(14, 3));
- result.push(id.substr(14, 3) % 2 == 0 ? "女" : "男");
- }
- /*
- 校验码Hash算法
- 中华人民共和国国家标准GB11643-1999
- ISO 7064:1983.MOD 11-2校验码算法:
- 1) 十七位数字本体码加权求和公式
- S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和
- Ai:表示第i位置上的身份证号码数字值
- Wi:表示第i位置上的加权因子
- Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2
- Wi也可表示为:2^(17 - i) % 11
- 2) 计算模
- Y = mod(S, 11)
- 3) 通过模得到对应的校验码V
- Y:0 1 2 3 4 5 6 7 8 9 10
- V:1 0 X 9 8 7 6 5 4 3 2
- V也可表示为:mod(12 - Y, 11), 如结果为10,则转换为X
- */
- var Y = 0;
- for (var i = 0; i < 17; i++) {
- var Ai = parseInt(id.substr(i, 1));
- var Wi = Math.pow(2, 17 - i) % 11;
- Y += Ai * Wi;
- }
- Y = (12 - Y % 11) % 11;
- var V = Y == 10 ? "X" : Y.toString();
- if (V != id.substr(17, 1).toUpperCase())
- return "【校验码】检测错误!"
- return result;
- }
3、已经转换好的“行政区划XML数据”,下载后将其保存为ChineseID.xml:
http://mengliao.blog.51cto.com/attachment/201204/876134_1334981976.xml
这个XML文件是用C#编写了一个小程序,对统计局的纯文本文件进行转换,使用了LINQ,核心代码如下:
- class Program
- {
- static void Main()
- {
- Console.WriteLine("开始生成XML文件...\n");
- using (StreamReader sr = new StreamReader("行政区划代码.txt"))
- {
- int Pid = 0, Cid = 0, Did = 0;
- XElement xe = new XElement("China");
- while (!sr.EndOfStream)
- {
- string[] items = sr.ReadLine().Split(',');
- if (items[0].Substring(2, 4) == "0000") // 后四位为0,省区级行政区
- {
- xe.Add(new XElement("Province",
- new XAttribute("P.ID", Pid++),
- new XElement("Name", items[1]),
- new XElement("Code", items[0])));
- Cid = 0; // 文件格式中按置省区、市县、三级行政区依次排列,故没开始一个新省区行政区,则市县行政区ID归0
- Console.Write("生成[{0}]...", items[1]);
- }
- else if (items[0].Substring(4, 2) == "00") // 否则后两位为0,市县级行政区
- {
- var query = (from p in xe.Elements()
- where p.Element("Code").Value.Substring(0, 2) == items[0].Substring(0, 2)
- select p).Single();
- query.Add(new XElement("City",
- new XAttribute("C.ID", Cid++),
- new XElement("Name", items[1]),
- new XElement("Code", items[0])));
- Did = 0; // 文件格式中按置省区、市县、三级行政区依次排列,故没开始一个新市县行政区,则三级行政区ID归0
- }
- else // 否则后两位不为0,三级行政区
- {
- // 分两步执行查询,提高性能
- var query = (from p in xe.Elements() // 获取所有Province元素
- where p.Element("Code").Value.Substring(0, 2) == items[0].Substring(0, 2)
- from c in p.Elements("City") // 获取该Province元素下的所有City元素
- where c.Element("Code").Value.Substring(2, 2) == items[0].Substring(2, 2)
- select c).Single();
- query.Add(new XElement("District",
- new XAttribute("D.ID", Did++),
- new XElement("Name", items[1]),
- new XElement("Code", items[0])));
- Console.Write(".");
- }
- }
- // 添加注释,并保存(可以使用XElement直接保存)
- XDocument xDoc = new XDocument(new XComment("梦辽软件2012.03生成"),
- new XComment("国家统计局截至2011.10.31县及县以上行政区划代码"));
- xDoc.Add(xe);
- xDoc.Save("ChineseID.xml");
- Console.Write("\n\nXML文件成功生成,按任意键退出...");
- Console.ReadKey();
- }
- }
- }
以上代码该有的注释都有了,就不多解释了。
本文转自 BlackAlpha 51CTO博客,原文链接:http://blog.51cto.com/mengliao/840373,如需转载请自行联系原作者