为啥要造
前几天开发一个项目,前端需要校验用人单位的统一社会信息用代码,然后网上搜了下感觉网上的代码都比较长(有的还需要积分才能t下载~~~),我们这个要求比较简单所以就用ES6重写了下。
校验规则
根据统一社会信息用代码编码规则, 这里的编码规则主要有以下六点:
- 18位的数字及大写英文字母(不包括
I/O/Z/S/V
); - 第1位是登记管理部门代码, 目前最新规则是1-9加上ANY,
([1-9ANY]{1})
; - 第2位是登记管理部门的机构类别代码,全部是数字,
([1-9]{1})
; - 第3至8位是行政区划代码,全部是数字,
([0-9]{6})
; - 第9至18位由数字和大写英文字母组成,
([0-9A-HJ-NP-RT-UW-Y]{10})
- 第18位是校验码,由前17位通过如下规则计算得到的(类似于身份证号的校验方式)
C 18 = 31 − M O D ( ∑ i = 1 17 C i × W i , 31 ) C_{18}=31-MOD(\sum_{i=1}^{17}C_{i}\times W_{i} ,31) C18=31−MOD(i=1∑17Ci×Wi,31)
你可以找到完整的 统一社会信息用代码编码规则 完整编码规则传送门.
戳我查看最新的 登记管理部门代码标识 国家标准第1号修改单传送门.
校验代码
好了,上面废话这么多,这就把代码奉上,这里我们是把这个校验放到工具文件里面然后在需要的地方引入,所以export
开头。如果是不从其他文件引入把export const
换成function
就好了。
看了下网上有说发证社会信息用代码校验计算通不过的情况校验码问题,经过测试确实存在,考虑到这种情况,加个了是否启用校验码校验参数(默认不启用)。
/**
* 校验统一社会信用代码
* @param val{String}
* @param checkEnable{Boolean}
* @returns {Boolean}
*/
export const isSocialCreditCode = (val, checkEnable = false) => {
// 前置条件即校验规则的第1至5要求
const pattern = /^([1-9ANY])([1-9])([0-9]{6})([0-9A-HJ-NP-RT-UW-Y]{10})$/;
if (!pattern.test(val) || !checkEnable) return pattern.test(val);
// 定义求模基数31
const MODE_BASE = 31;
// 空字符串
const EMPTY_STR= "";
// 代码字符数组, 其下标作为代码字符数值
const CHAR_CODES = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'T', 'U', 'W', 'X', 'Y'];
// 各位置序号上的加权因子
const WEIGHT_FACTORS = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
// 初始化一个与信用代码等长的空的代码字符数值数组
// 用于和加权因子进行乘积求和运算
let values = new Array(val.length);
// 初始化求和值
let sum = 0;
// 将信用代码字符串转换为代码字符数值数组
val.split(EMPTY_STR).forEach((item, index) => values[index] = CHAR_CODES.findIndex(elem => elem === item));
// 删除最后一位元素(第18位不参与求和计算)
const endValue = values.pop();
// 将字符数组数值逐个元素与加权因子乘积求和
WEIGHT_FACTORS.forEach((item, index) => sum += item * values[index]);
// 换算校验代码字符
// let checkCode = CHAR_CODES[MODE_BASE - sum % MODE_BASE];
// return val.substring(17, 18) === checkCode;
// 不换算回字符了,直接用第18位的数值进行比较
return endValue === (MODE_BASE - sum % MODE_BASE);
}