车辆识别码VIN校验位计算方法及实现

车辆识别码VIN校验工具

参考 GB16735—2019《道路车辆 车辆识别代号(VIN)》

VIN组成

在这里插入图片描述
在这里插入图片描述

年份

在这里插入图片描述

校验位

在这里插入图片描述

代码
public class VinUtil {
    
    /**
     * 加权值. 因为第9位权重为0,所以原来是什么字符不影响结果,可以方便后面计算
     */
    static int[] weightValue = {8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2};
    
    /**
     * VIN码各位数字的“对应值”.
     */
    static Map<Character, Integer> vinValueMap = new HashMap<>();
    
    /**
     * 校验值.
     */
    static char[] checkBit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'X'};
    
    /**
     * VIN中不会包含 I、O、Q 三个英文字母.
     */
    static String regex = "^[A-HJ-NPR-Z\\d]{8}[X\\d][A-HJ-NPR-Z\\d]{3}\\d{5}$";
    
    static {
        vinValueMap.put('0', 0);
        vinValueMap.put('1', 1);
        vinValueMap.put('2', 2);
        vinValueMap.put('3', 3);
        vinValueMap.put('4', 4);
        vinValueMap.put('5', 5);
        vinValueMap.put('6', 6);
        vinValueMap.put('7', 7);
        vinValueMap.put('8', 8);
        vinValueMap.put('9', 9);
        vinValueMap.put('A', 1);
        vinValueMap.put('B', 2);
        vinValueMap.put('C', 3);
        vinValueMap.put('D', 4);
        vinValueMap.put('E', 5);
        vinValueMap.put('F', 6);
        vinValueMap.put('G', 7);
        vinValueMap.put('H', 8);
        vinValueMap.put('J', 1);
        vinValueMap.put('K', 2);
        vinValueMap.put('M', 4);
        vinValueMap.put('L', 3);
        vinValueMap.put('N', 5);
        vinValueMap.put('P', 7);
        vinValueMap.put('R', 9);
        vinValueMap.put('S', 2);
        vinValueMap.put('T', 3);
        vinValueMap.put('U', 4);
        vinValueMap.put('V', 5);
        vinValueMap.put('W', 6);
        vinValueMap.put('X', 7);
        vinValueMap.put('Y', 8);
        vinValueMap.put('Z', 9);
    }
    
    /**
     * 检验VIN格式.
     *
     * @param vin 车架号
     * @return boolean
     */
    public static boolean checkVin(String vin) {
        if (vin == null) {
            return false;
        }
        String upperVin = vin.toUpperCase();
        // 排除长度不为17 字母O、I、Q
        if (!Pattern.matches(regex, upperVin)) {
            return false;
        }
        char[] vinArr = upperVin.toCharArray();
        int amount = 0;
        for (int i = 0; i < vinArr.length; i++) {
            // VIN码从从第一位开始,码数字的对应值×该位的加权值,计算全部17位的乘积值相加
            amount += vinValueMap.get(vinArr[i]) * weightValue[i];
        }
        // VIN码从从第一位开始,码数字的对应值×该位的加权值,计算全部17位的乘积值相加除以11,所得的余数,即为第九位校验值.
        // 若余数为10,即为字母X
        boolean bitFlag = checkBit[amount % 11] == vinArr[8];
        // 第10位年份 不包含数字0、I、O、Q、U、Z
        boolean flag = vinArr[9] == '0' || vinArr[9] == 'I' || vinArr[9] == 'O' || vinArr[9] == 'Q' || vinArr[9] == 'U'
                || vinArr[9] == 'Z';
        return bitFlag && !flag;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值