js 正则校验车架号VIN
正则要求:
- 由大写字母和数字组成,长度17位;
- 字母不会出现O、Q、I三个字母;
- 第9位只能是【0-9】的数字和字母X;
- 第13-17位只能是数字;
根据百度、谷歌只搜搜到这个,还请各位大佬们赐教
现在只实现了1,2两个条件;如下:let reg=/^[A-HJ-NPR-Z\d]{17}$/
根据规则一个个罗列出来不就是了?/^[A-HJ-NPR-Z\d]{8}[X\d][A-HJ-NPR-Z\d]{3}\d{5}$/
简单的是/^[A-HJ-NPR-Z\d]{8}[X\d][A-HJ-NPR-Z\d]{3}\d{5}$/
这个规则,不过估计类似身份证号,里面应该还包括校验位,估计校验位就是第9位,所以完整判别估计不能只由规则式判定,还需要检测校验位。
检索到 https://baijiahao.baidu.com/s...
所以完整的还需要进一步进行判断。
这里有校验位计算方法 https://blog.csdn.net/shenhon...
var checkVIN=function(VIN){
if(typeof(VIN)!='string') return false;
if(VIN.length!=17) return false;
VIN=VIN.toUpperCase();
RE==/^[A-HJ-NPR-Z\d]{8}[X\d][A-HJ-NPR-Z\d]{3}\d{5}$/
if(!RE.test(VIN)) return false;
let cOT={
'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,
'8':8,'9':9,'A':1,'B':2,'C':3,'D':4,'E':5,'F':6,
'G':7,'H':8,'J':1,'K':2,'L':3,'M':4,'N':5,'P':7,
'R':9,'S':2,'T':3,'U':4,'V':5,'W':6,'X':7,'Y':8,
'Z':9
};
let xWT=[8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2]; // 因为第9位权重为0,所以原来是什么字符不影响结果,可以方便后面计算
let sum=0;
VINs=VIN.split('');
for(let i=0;i<17;i++){
sum=sum + cOT[ VINs[i] ] * xWT[i];
}
let cT=['0','1','2','3','4','5','6','7','8','9','X'];
if( cT[ (sum%11) ] == VINs[8]) return true;
return false;
}
@xdsnet 的回答已经很全面了,先用正则表达式快速检查,再做校验。我这里只是对代码做一个纯粹的技术探讨。
关于 cOT
的生成
手写太累,可以
const cOT = (() => {
const entries = [
"0123456789",
" ABCDEFGH",
" JKLMNOPQR",
" STUVWXYZ"
].flatMap(
// Array.from 把字符串拆分成字符数组(主要是手写字符数组太累)
// 根据字符位置生成 entry,比如 ['J', 1]
// 完了进行 flat,把多组数组扁平化
s => Array.from(s).map((c, i) => [c, i])
);
// 从 entires 生成对象,这个对象的键包含了空格、I、O 和 Q
// 如果将上面的 IOQ 替换成空格,这里多的就只有空格
const map = Object.fromEntries(entries);
// 删除多余的键(其实不删也没关系,因为之前已经用正则已将这些字符排除掉了)
return Array.from(" IOQ").reduce((m, c) => (delete m[c], m), map);
})();
这段代码只在初始化的时候执行一次,对效率没啥影响。如果还是想直接定义成常量,将上述代码的执行结果在控制台中用 JSON.stringify(cOT)
输出就是。
关于计算 SUM
效率并不如原生循环,只是把计算过程封装在一句话里。用 IIFE 也可以达到同样的效果。
const sum = Array.from(VIN)
.map((c, i) => cOT[c] * xWT[i])
.reduce((s, v) => s + v, 0);
关于 10 => 'X'
直接用数组很直接,关无毛病。
这是个时间换空间的写法(其实对于这点空间,没啥卵用),
const vcode = (mod => mod === 10 ? "X" : mod.toString())(sum % 11);