中国大陆居民身份证号码第18位为校验码,用来验证本体码的准确性。
校验码采用ISO 7064:1983,MOD 11-2校验码系统。
因此可以对身份证号码第18位进行校验,来验证身份证号码在算法层面是否合法。
由于校验码系统算法的原因,如果身份证号码前17位中有多位错误,仍有可能通过验证。
GB11643-1999中对校验码描述如下图
JavaScript实现代码如下
开发版本
/*
* File: MOD11-2.js
* Author: 张泽楠
* Copyright ©2020 张泽楠, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
* Time: 2020-11-8 18:25
*/
/*
* ISO 7064:1983,MOD 11-2 校验码系统
*
* @param:
* id 待校验身份证号码,请使用字符串传入
* @return:
* ture 通过MOD11-2校验
* false 未通过MOD11-2校验
* NaN 传入参数存在无法解析的非数字字符
* -1 传入参数长度有误
*/
function MOD11_2(id) {
/*
* ISO 7064:1983,MOD 11-2 校验码系统的校验算法
*
* i: 位置索引
* wi: 权重
* ai: 身份证号码(身份证号码中使用罗马数字"Ⅹ"代替数字10)
*
* 权重wi:
* wi = 2^(18-i) mod 11
*
* 校验码a18:
* ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
* │i │1 │2 │3 │4 │5 │6 │7 │8 │9 │10│11│12│13│14│15│16│17│18│
* ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
* │wi│7 │9 │10│5 │8 │4 │2 │1 │6 │3 │7 │9 │10│5 │8 │4 │2 │ │
* ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤
* │ai│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
* └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
*
* 计算公式:
* ┌ ┐
* │ 17 │
* a18 = ( 12 - ( │ ∑ (wi*ai) │ mod 11 ) ) mod 11
* │ i=1 │
* └ ┘
*/
// --------------- 判断传入参数长度 -----------------
if (18 != id.length) {
console.error(`
<MOD11-2.js>
error: 传入参数长度有误
parameter: id = ${id}
require: id.length == ${18}
found: id.length == ${id.length}
return: -1
`);
return -1;
}
// --------------- 将字符串转换为数组 -----------------
var idList = id.split('');
if ('X' == idList[17] || 'x' == idList[17] || 'Ⅹ' == idList[17]) {
idList[17] = '10'
}
for (var i = 0; i < 18; i++) {
idList[i] = parseInt(idList[i]);
if (isNaN(idList[i])) {
console.error(`
<MOD11-2.js>
error: 传入参数存在无法解析的非数字字符
parameter: id[${i+1}] = ${id[i]}
require: isNaN(id[${i+1}]) == ${false}
found: isNaN(id[${i+1}]) == ${true}
return: NaN
`);
return NaN;
}
}
// --------------- 权重wi -----------------
// wi只与位置索引有关,在此不做重复计算,直接声明weightList并赋值
// var weightList = [];
// for(var i=1; i<18; i++){
// weightList.push((Math.pow(2, 18-i))%11);
// }
var weightList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
// --------------- 根据计算公式计算 -----------------
var sum = 0;
for (var i = 0; i < 17; i++) {
sum += weightList[i] * idList[i];
}
var checkCode = sum % 11;
checkCode = 12 - checkCode;
checkCode %= 11;
// --------------- 校验完成 -----------------
if (checkCode != idList[17]) {
console.error(`
<MOD11-2.js>
error: 未通过MOD11-2校验
parameter: id = ${id}
require: id[18] == ${checkCode}
found: id[18] == ${idList[17]}
return: false
`);
} else {
console.log(`
<MOD11-2.js>
success: 通过MOD11-2校验
parameter: id = ${id}
require: id[18] == ${checkCode}
found: id[18] == ${idList[17]}
return: true
`);
}
return checkCode == idList[17];
};
console.info(
`===============================================
File: MOD11-2.js
Author: 张泽楠
Copyright ©2020 张泽楠, All Rights Reserved
SPDX-License-Identifier: Apache-2.0
Time: 2020-11-8 18:25
===============================================
function MOD11_2(id)
-----------------------------------------------
ISO 7064:1983,MOD 11-2 校验码系统
@param:
id 待校验身份证号码,请使用字符串传入
@return:
ture 通过MOD11-2校验
false 未通过MOD11-2校验
NaN 传入参数存在无法解析的非数字字符
-1 传入参数长度有误
===============================================`);
生产版本
function MOD11_2(id) {
/*
* File: MOD11-2.js
* Author: 张泽楠
* Copyright ©2020 张泽楠, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
* Time: 2020-11-8 18:25
*/
if (18 != id.length) {
return -1;
}
var idList = id.split('');
if ('X' == idList[17] || 'x' == idList[17] || 'Ⅹ' == idList[17]) {
idList[17] = '10'
}
for (var i = 0; i < 18; i++) {
idList[i] = parseInt(idList[i]);
if (isNaN(idList[i])) {
return NaN;
}
}
var weightList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
var sum = 0;
for (var i = 0; i < 17; i++) {
sum += weightList[i] * idList[i];
}
var checkCode = sum % 11;
checkCode = 12 - checkCode;
checkCode %= 11;
return checkCode == idList[17];
};