diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/VIN.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/VIN.java new file mode 100644 index 000000000..b7480f578 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/data/VIN.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.data; + +import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.map.MapUtil; +import org.dromara.hutool.core.regex.PatternPool; +import org.dromara.hutool.core.regex.ReUtil; + +import java.time.Year; +import java.util.HashMap; +import java.util.Map; + +/** + * VIN是Vehicle Identification Number的缩写,即车辆识别号码。VIN码是全球通行的车辆唯一标识符,由17位数字和字母组成。 + *

+ * 不同位数代表着不同意义,具体解释如下: + *

+ * VIN码可以找到汽车详细的个人、工程、制造方面的信息,是判定一个汽车合法性及其历史的重要依据。 + *

+ * 本实现参考以下标准: + *

+ * + * @author dax + * @since 6.0.0 + */ +public class VIN { + /** + * 加权系数,见附录A,表A.3 + */ + private static final int[] WEIGHT = {8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2}; + private static final int YEAR_LOOP = 30; + private static final char[] YEAR_ID = { + 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'J', 'K', + 'L', 'M', 'N', 'P', 'R', + 'S', 'T', 'V', 'W', 'X', + 'Y', '1', '2', '3', '4', + '5', '6', '7', '8', '9' + }; + private static final Map YEAR_MAP; + + static { + final Map yearMap = new HashMap<>(YEAR_ID.length, 1); + for (int i = 0; i < YEAR_ID.length; i++) { + yearMap.put(YEAR_ID[i], i); + } + YEAR_MAP = MapUtil.view(yearMap); + } + + /** + * 创建VIN + * + * @param vinCode VIN码 + * @return VIN对象 + */ + public static VIN of(final String vinCode) { + return new VIN(vinCode); + } + + private final String code; + + /** + * 构造 + * + * @param vinCode VIN码 + */ + public VIN(final String vinCode) { + Assert.isTrue(verify(vinCode), "Invalid VIN code!"); + this.code = vinCode; + } + + /** + * 获取VIN码 + * + * @return VIN码 + */ + public String getCode(){ + return this.code; + } + + /** + * 获取国家或地区代码 + * + * @return 国家或地区代码 + */ + public String getCountryCode() { + return this.code.substring(0, 2); + } + + /** + * 获取世界制造厂识别代号WMI(World Manufacturer Identifier)
+ * 对年产量大于或等于1000辆的完整车辆或非完整车辆制造,车辆识别代号的第一部分为世界制造)厂识别代号(WMI)
+ * 对年产量小于1000辆的完整车辆和/或非完整车辆制造厂,第三部分的三、四、五位与第一部分的三位字码一起构成世界制造厂识别代号(WMI) + * + * @return WMI + */ + public String getWMI() { + final String wmi = this.code.substring(0, 3); + return isLessThan1000() ? wmi + this.code.substring(11, 14) : wmi; + } + + /** + * 是否是年产量小于1000的车辆制造厂 + * + * @return 是否年产量小于1000 + */ + public boolean isLessThan1000() { + return '9' == this.code.charAt(2); + } + + /** + * 获取车辆说明部分 VDS(Vehicle Descriptor section) + * + * @return VDS值 + */ + public String getVDS() { + return this.code.substring(3, 9); + } + + /** + * 获取车辆特征代码(Vehicle Descriptor Code),相对于VDS,不包含校验位。 + * + * @return 车辆特征代码 + */ + public String getVehicleDescriptorCode() { + return this.code.substring(3, 8); + } + + /** + * 获取车辆指示部分 VIS(Vehicle Indicator Section) + * + * @return VIS + */ + public String getVIS() { + return this.code.substring(9); + } + + /** + * Get year. + * + * @return the year + */ + public Year getYear() { + return getYear(1); + } + + /** + * 获取装配厂字码 + * + * @return 由厂家自行定义的装配厂字码 string + */ + public char getOemCode() { + return this.code.charAt(10); + } + + /** + * Gets year. + * + * @param multiple 1 代表从 1980年开始的第一个30年 + * @return the year + */ + public Year getYear(final int multiple) { + final int year = 1980 + YEAR_LOOP * multiple + YEAR_MAP.get(this.code.charAt(9)) % YEAR_LOOP; + return Year.of(year); + } + + /** + * 生产序号 + *

+ * 年产量大于1000为6位,年产量小于1000的为3位 + * + * @return 生产序号 string + */ + public String getProdNo() { + return this.code.substring(isLessThan1000() ? 14 : 11, 17); + } + + /** + * 校验VIN码有效性,要求: + *

+ * + * @param vinCode VIN码 + * @return 是否有效 + */ + public static boolean verify(final String vinCode) { + Assert.notBlank(vinCode, "VIN code must be not blank!"); + if (!ReUtil.isMatch(PatternPool.CAR_VIN, vinCode)) { + return false; + } + + return vinCode.charAt(8) == calculateVerifyCode(vinCode); + } + + /** + * 计算校验值,见附录A + * + * @param vinCode VIN码 + * @return 校验值 + */ + private static char calculateVerifyCode(final String vinCode) { + int sum = 0; + for (int i = 0; i < 17; i++) { + sum += getWeightFactor(vinCode, i); + } + + final int factor = sum % 11; + return factor != 10 ? (char) (factor + '0') : 'X'; + } + + /** + * 获取对应位置字符的权重因子 + * + * @param vinCode VIN码 + * @param i 位置 + * @return 权重因子 + */ + private static int getWeightFactor(final String vinCode, final int i) { + final char c = vinCode.charAt(i); + return getVinValue(c) * WEIGHT[i]; + } + + /** + * 获取字母对应值(见:附录A,表A.2) + * + * @param vinCodeChar VIN编码中的字符 + * @return 对应值 + */ + private static int getVinValue(final char vinCodeChar) { + switch (vinCodeChar) { + case '0': + return 0; + case '1': + case 'J': + case 'A': + return 1; + case '2': + case 'S': + case 'K': + case 'B': + return 2; + case '3': + case 'T': + case 'L': + case 'C': + return 3; + case '4': + case 'U': + case 'M': + case 'D': + return 4; + case '5': + case 'V': + case 'N': + case 'E': + return 5; + case '6': + case 'W': + case 'F': + return 6; + case '7': + case 'P': + case 'X': + case 'G': + return 7; + case '8': + case 'Y': + case 'H': + return 8; + case '9': + case 'Z': + case 'R': + return 9; + } + throw new IllegalArgumentException("Invalid VIN char: " + vinCodeChar); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/AlphanumericVinCode.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/AlphanumericVinCode.java deleted file mode 100644 index 0aba7ba30..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/AlphanumericVinCode.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -/** - * 可以是字母或者数字的字码 - * - * @author dax - * @since 2023 /5/14 17:56 - */ -class AlphanumericVinCode implements MaskVinCode { - private final String code; - private final int index; - private final int mask; - - - /** - * 该构造会校验字码是否符合GB16735标准 - * - * @param code 字码值 - * @param index 索引位 - */ - AlphanumericVinCode(String code, int index) { - this.code = code; - this.index = index; - int weight = WEIGHT_FACTORS.get(index); - mask = NUMERIC.matcher(this.code).matches() ? - Integer.parseInt(this.code) * weight : - VinCodeMaskEnum.valueOf(this.code).getMaskCode() * weight; - } - - @Override - public String getCode() { - return code; - } - - @Override - public int getMask() { - return mask; - } - - @Override - public int getIndex() { - return index; - } - - @Override - public String toString() { - return "AlphanumericVinCode{" + - "code='" + code + '\'' + - ", index=" + index + - ", mask=" + mask + - '}'; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/MaskVinCode.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/MaskVinCode.java deleted file mode 100644 index 888204e3c..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/MaskVinCode.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -/** - * 支持掩码的字码 - * - * @author dax - * @since 2023 /5/15 10:43 - */ -interface MaskVinCode extends VinCode { - /** - * 字码权重因子 - */ - List WEIGHT_FACTORS = Arrays.asList(8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2); - /** - * 数字位校验 - */ - Pattern NUMERIC = Pattern.compile("^\\d$"); - - /** - * 获取掩码,字码编码*加权值 - * - * @return the mask - */ - int getMask(); - - /** - * 所在位置索引,[0,16] - * - * @return the index - */ - int getIndex(); -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/NumericVinCode.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/NumericVinCode.java deleted file mode 100644 index 706cfd7f7..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/NumericVinCode.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -/** - * 数字字码. - * - * @author dax - * @since 2023 /5/14 17:42 - */ -class NumericVinCode implements MaskVinCode { - private final String code; - private final int index; - private final int mask; - - /** - * 该构造会校验字码是否符合GB16735标准 - * - * @param code 字码值 - * @param index 索引位 - * @throws IllegalArgumentException 校验 - */ - NumericVinCode(String code, int index) throws IllegalArgumentException { - - if (!NUMERIC.matcher(code).matches()) { - throw new IllegalArgumentException("索引为 " + index + " 的字码必须是数字"); - } - this.code = code; - this.index = index; - this.mask = Integer.parseInt(code) * WEIGHT_FACTORS.get(index); - } - - @Override - public String getCode() { - return code; - } - - @Override - public int getMask() { - return mask; - } - - @Override - public int getIndex() { - return index; - } - - - @Override - public String toString() { - return "NumericCode{" + - "code='" + code + '\'' + - ", index=" + index + - ", mask=" + mask + - '}'; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vds.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vds.java deleted file mode 100644 index 1b42c11bc..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vds.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * VDS - * - * @author dax - * @since 2023 /5/15 9:37 - */ -class Vds implements VinCode { - - private final List vdCode; - private final AlphanumericVinCode checksum; - private final String code; - private final int mask; - - /** - * Instantiates a new Vds. - * - * @param vdCode the vd code - */ - Vds(List vdCode) { - this.vdCode = vdCode.subList(0, 5); - this.checksum = vdCode.get(5); - this.code = vdCode.stream().map(AlphanumericVinCode::getCode).collect(Collectors.joining()); - this.mask = vdCode.stream().mapToInt(AlphanumericVinCode::getMask).sum(); - } - - /** - * 从VIN生成VDS - * - * @param vin the vin - * @return the vds - */ - public static Vds from(String vin) { - List vdCode = IntStream.range(3, 9) - .mapToObj(index -> - new AlphanumericVinCode(String.valueOf(vin.charAt(index)), index)) - .collect(Collectors.toList()); - return new Vds(vdCode); - } - - /** - * Gets vd code. - * - * @return the vd code - */ - List getVdCode() { - return vdCode; - } - - /** - * Gets checksum. - * - * @return the checksum - */ - AlphanumericVinCode getChecksum() { - return checksum; - } - - @Override - public String getCode() { - return code; - } - - /** - * Gets mask. - * - * @return the mask - */ - int getMask() { - return mask; - } - - @Override - public String toString() { - return "Vds{" + - "vdCode=" + vdCode + - ", checksum=" + checksum + - ", code='" + code + '\'' + - ", mask=" + mask + - '}'; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vin.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vin.java deleted file mode 100644 index 086083866..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vin.java +++ /dev/null @@ -1,211 +0,0 @@ -package org.dromara.hutool.core.data.vin; - - -import java.time.Year; -import java.util.Objects; -import java.util.regex.Pattern; -import java.util.stream.IntStream; - -/** - * VIN是Vehicle Identification Number的缩写,即车辆识别号码。VIN码是全球通行的车辆唯一标识符,由17位数字和字母组成。 - *

- * 不同位数代表着不同意义,具体解释如下: - *

    - *
  • 1-3位:制造商标示符,代表车辆制造商信息
  • - *
  • 4-8位:车型识别代码,代表车辆品牌、车系、车型及其排量等信息
  • - *
  • 9位:校验位,通过公式计算出来,用于验证VIN码的正确性
  • - *
  • 10位:年份代号,代表车辆生产的年份
  • - *
  • 11位:工厂代码,代表车辆生产工厂信息
  • - *
  • 12-17位:流水号,代表车辆的生产顺序号
  • - *
- * VIN码可以找到汽车详细的个人、工程、制造方面的信息,是判定一个汽车合法性及其历史的重要依据。 - *

- * 本实现参考以下标准: - *

- * - * @author dax - * @since 2023 /5/15 9:40 - */ -public final class Vin implements VinCode { - private static final Pattern GB16735_VIN_REGEX = Pattern.compile("^[A-HJ-NPR-Z\\d]{8}[X\\d][A-HJ-NPR-Z\\d]{8}$"); - private final Wmi wmi; - private final Vds vds; - private final Vis vis; - private final String code; - - /** - * Instantiates a new Vin. - * - * @param wmi the wmi - * @param vds the vds - * @param vis the vis - * @param code the code - */ - Vin(Wmi wmi, Vds vds, Vis vis, String code) { - this.wmi = wmi; - this.vds = vds; - this.vis = vis; - this.code = code; - } - - /** - * 从VIN字符串生成{@code Vin}对象 - * - * @param vin VIN字符串 - * @return VIN对象 vin - */ - public static Vin of(String vin) throws IllegalArgumentException { - if (!GB16735_VIN_REGEX.matcher(vin).matches()) { - throw new IllegalArgumentException("VIN格式不正确,需满足正则 " + GB16735_VIN_REGEX.pattern()); - } - Wmi wmi = Wmi.from(vin); - Vds vds = Vds.from(vin); - Vis vis = Vis.from(vin); - int factor = (wmi.getMask() + vds.getMask() + vis.getMask()) % 11; - String checked = factor != 10 ? String.valueOf(factor) : "X"; - if (!Objects.equals(vds.getChecksum().getCode(), checked)) { - throw new IllegalArgumentException("VIN校验不通过"); - } - return new Vin(wmi, vds, vis, vin); - } - - /** - * 仅判断一个字符串是否符合VIN规则 - * - * @param vinStr vinStr - * @return {@code true} 符合 - */ - public static boolean isValidVinCode(String vinStr) { - if (GB16735_VIN_REGEX.matcher(vinStr).matches()) { - int weights = IntStream.range(0, 17) - .map(i -> calculateWeight(vinStr, i)) - .sum(); - int factor = weights % 11; - char checked = factor != 10 ? (char) (factor + '0') : 'X'; - return vinStr.charAt(8) == checked; - } - return false; - } - - private static int calculateWeight(String vinStr, int i) { - char c = vinStr.charAt(i); - Integer factor = MaskVinCode.WEIGHT_FACTORS.get(i); - return c <= '9' ? - Character.getNumericValue(c) * factor : - VinCodeMaskEnum.valueOf(String.valueOf(c)).getMaskCode() * factor; - } - - /** - * 标识一个国家或者地区 - * - * @return the string - */ - public String geoCode() { - String wmiCode = this.wmi.getCode(); - return wmiCode.substring(0, 2); - } - - /** - * 制造厂标识码 - *

- * 年产量大于1000为符合GB16737规定的{@link Wmi},年产量小于1000固定为9,需要结合VIN的第12、13、14位字码确定唯一 - * - * @return 主机厂识别码 string - */ - public String manufacturerCode() { - String wmiCode = this.wmi.getCode(); - return isLessThan1000() ? - wmiCode.concat(this.vis.getProdNoStr().substring(0, 3)) : wmiCode; - } - - /** - * 是否是年产量小于1000的车辆制造厂 - * - * @return 是否年产量小于1000 boolean - */ - public boolean isLessThan1000() { - return this.wmi.isLessThan1000(); - } - - /** - * 获取WMI码 - * - * @return WMI值 string - */ - public String wmiCode() { - return wmi.getCode(); - } - - /** - * 获取车辆特征描述码 - * - * @return VDS值 string - */ - public String vdsCode() { - return this.vds.getCode().substring(0, 5); - } - - /** - * 获取默认车型年份,接近于本年度 - * - * @return the int - */ - public Year defaultYear() { - return this.year(1); - } - - /** - * 获取车型年份 - *

- * 自1980年起,30年一个周期 - * - * @param multiple 1 代表从 1980年开始的第一个30年 - * @return 返回年份对象 year - * @see 年份编码模型 - */ - public Year year(int multiple) { - return this.vis.getYear(multiple); - } - - /** - * 生产序号 - *

- * 年产量大于1000为6位,年产量小于1000的为3位 - * - * @return 生产序号 string - */ - public String prodNo() { - String prodNoStr = this.vis.getProdNoStr(); - return isLessThan1000() ? - prodNoStr.substring(3, 6) : prodNoStr; - } - - /** - * 获取装配厂字码 - * - * @return 由厂家自行定义的装配厂字码 string - */ - public String oemCode() { - return this.vis.getOem().getCode(); - } - - @Override - public String getCode() { - return code; - } - - @Override - public String toString() { - return "Vin{" + - "wmi=" + wmi + - ", vds=" + vds + - ", vis=" + vis + - ", code='" + code + '\'' + - '}'; - } - -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCode.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCode.java deleted file mode 100644 index 6b7542cb2..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCode.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.dromara.hutool.core.data.vin; - - -/** - * 汽车Vin字码抽象. - * - * @author dax - * @since 2023 /5/14 17:42 - */ -interface VinCode { - - /** - * 获取字码值 - * - * @return the code - */ - String getCode(); -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCodeMaskEnum.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCodeMaskEnum.java deleted file mode 100644 index 458d89795..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/VinCodeMaskEnum.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -/** - * Vin掩码枚举 - * - * @author dax - * @since 2023 /5/15 10:49 - */ -enum VinCodeMaskEnum { - /** - * A 掩码. - */ - A(1), - /** - * B 掩码. - */ - B(2), - /** - * C 掩码. - */ - C(3), - /** - * D 掩码. - */ - D(4), - /** - * E 掩码. - */ - E(5), - /** - * F 掩码. - */ - F(6), - /** - * G 掩码. - */ - G(7), - /** - * H 掩码. - */ - H(8), - /** - * J 掩码. - */ - J(1), - /** - * K 掩码. - */ - K(2), - /** - * L 掩码. - */ - L(3), - /** - * M 掩码. - */ - M(4), - /** - * N 掩码. - */ - N(5), - /** - * P 掩码. - */ - P(7), - /** - * R 掩码. - */ - R(9), - /** - * S 掩码. - */ - S(2), - /** - * T 掩码. - */ - T(3), - /** - * U 掩码. - */ - U(4), - /** - * V 掩码. - */ - V(5), - /** - * W 掩码. - */ - W(6), - /** - * X 掩码. - */ - X(7), - /** - * Y 掩码. - */ - Y(8), - /** - * Z 掩码. - */ - Z(9); - - private final int maskCode; - - VinCodeMaskEnum(int maskCode) { - this.maskCode = maskCode; - } - - /** - * 获取掩码值. - * - * @return the mask code - */ - public int getMaskCode() { - return maskCode; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vis.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vis.java deleted file mode 100644 index 8bcaaf8e2..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Vis.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -import java.time.Year; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * VIS - * - * @author dax - * @since 2023 /5/15 12:07 - */ -class Vis implements VinCode { - - private static final int YEAR_LOOP = 30; - private static final List YEAR_ID = Arrays.asList( - "A", "B", "C", "D", "E", - "F", "G", "H", "J", "K", - "L", "M", "N", "P", "R", - "S", "T", "V", "W", "X", - "Y", "1", "2", "3", "4", - "5", "6", "7", "8", "9"); - private static final Map YEAR_MAP = new HashMap<>(); - - static { - for (int i = 0; i < YEAR_ID.size(); i++) { - YEAR_MAP.put(YEAR_ID.get(i), i); - } - } - - private final AlphanumericVinCode year; - private final AlphanumericVinCode oem; - private final List prodNo; - private final String prodNoStr; - private final String code; - private final int mask; - - /** - * Instantiates a new Vis. - * - * @param year the year - * @param oem the oem - * @param prodNo the prod no - */ - Vis(AlphanumericVinCode year, AlphanumericVinCode oem, List prodNo) { - this.year = year; - this.oem = oem; - this.prodNo = prodNo; - this.prodNoStr = prodNo.stream().map(MaskVinCode::getCode).collect(Collectors.joining()); - this.code = year.getCode() + oem.getCode() + prodNo.stream() - .map(MaskVinCode::getCode) - .collect(Collectors.joining()); - this.mask = year.getMask() + oem.getMask() + prodNo.stream().mapToInt(MaskVinCode::getMask).sum(); - } - - /** - * 从VIN生成VIS - * - * @param vin the vin - * @return the vis - */ - static Vis from(String vin) { - AlphanumericVinCode year = new AlphanumericVinCode(String.valueOf(vin.charAt(9)), 9); - AlphanumericVinCode factory = new AlphanumericVinCode(String.valueOf(vin.charAt(10)), 10); - List codes = IntStream.range(11, 17) - .mapToObj(index -> index < 14 ? new AlphanumericVinCode(String.valueOf(vin.charAt(index)), index) : - new NumericVinCode(String.valueOf(vin.charAt(index)), index)) - .collect(Collectors.toList()); - return new Vis(year, factory, codes); - } - - /** - * Gets year. - * - * @param multiple the multiple - * @return the year - */ - Year getYear(int multiple) { - int year = 1980 + YEAR_LOOP * multiple + YEAR_MAP.get(this.year.getCode()) % YEAR_LOOP; - return Year.of(year); - } - - /** - * Gets oem. - * - * @return the oem - */ - AlphanumericVinCode getOem() { - return oem; - } - - - /** - * Gets prod no. - * - * @return the prod no - */ - List getProdNo() { - return prodNo; - } - - /** - * Gets prod no str. - * - * @return the prod no str - */ - String getProdNoStr() { - return prodNoStr; - } - - /** - * Gets mask. - * - * @return the mask - */ - int getMask() { - return mask; - } - - @Override - public String getCode() { - return code; - } - - @Override - public String toString() { - return "Vis{" + - "year=" + year + - ", oem=" + oem + - ", prodNo=" + prodNo + - ", code='" + code + '\'' + - ", mask=" + mask + - '}'; - } -} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Wmi.java b/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Wmi.java deleted file mode 100644 index 740507458..000000000 --- a/hutool-core/src/main/java/org/dromara/hutool/core/data/vin/Wmi.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.dromara.hutool.core.data.vin; - -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * The type Wmi. - * - * @author dax - * @since 2023 /5/15 9:25 - */ -class Wmi implements VinCode { - private final String code; - private final int mask; - /** - * The Wmi codes. - */ - List wmiCodes; - - /** - * Instantiates a new Wmi. - * - * @param wmiCodes the wmi codes - */ - Wmi(List wmiCodes) { - this.wmiCodes = wmiCodes; - AtomicInteger mask = new AtomicInteger(); - this.code = wmiCodes.stream() - .peek(alphanumericCode -> mask.addAndGet(alphanumericCode.getMask())) - .map(AlphanumericVinCode::getCode) - .collect(Collectors.joining()); - this.mask = mask.get(); - } - - /** - * 从VIN生成WMI - * - * @param vin the vin - * @return the wmi - */ - static Wmi from(String vin) { - List codes = IntStream.range(0, 3) - .mapToObj(index -> - new AlphanumericVinCode(String.valueOf(vin.charAt(index)), index)) - .collect(Collectors.toList()); - return new Wmi(codes); - } - - @Override - public String getCode() { - return code; - } - - @Override - public String toString() { - return "Wmi{" + - "wmiCodes=" + wmiCodes + - ", code='" + code + '\'' + - ", mask=" + mask + - '}'; - } - - /** - * Gets mask. - * - * @return the mask - */ - int getMask() { - return mask; - } - - - /** - * 是否是年产量小于1000的车辆制造厂 - * - * @return the boolean - */ - boolean isLessThan1000() { - return this.code.matches("^.*9$"); - } -} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/data/VinTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/data/VinTest.java index b07bfff4f..91137f561 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/data/VinTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/data/VinTest.java @@ -1,6 +1,5 @@ package org.dromara.hutool.core.data; -import org.dromara.hutool.core.data.vin.Vin; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -8,34 +7,29 @@ import java.time.Year; /** * @author VampireAchao - * @since 2023/5/31 14:43 */ public class VinTest { @Test public void parseVinTest() { - String vinStr = "HE9XR1C48PS083871"; - Vin vin = Vin.of(vinStr); + final String vinStr = "HE9XR1C48PS083871"; + final VIN vin = VIN.of(vinStr); // VIN Assertions.assertEquals("HE9XR1C48PS083871", vin.getCode()); - // 是否合法 - Assertions.assertTrue(Vin.isValidVinCode(vinStr)); // 年产量<1000 Assertions.assertTrue(vin.isLessThan1000()); - // WMI - Assertions.assertEquals("HE9", vin.wmiCode()); // 地理区域码 - Assertions.assertEquals("HE", vin.geoCode()); - // 主机厂代码 - Assertions.assertEquals("HE9083", vin.manufacturerCode()); + Assertions.assertEquals("HE", vin.getCountryCode()); + // WMI主机厂代码 + Assertions.assertEquals("HE9083", vin.getWMI()); // VDS - Assertions.assertEquals("XR1C4", vin.vdsCode()); + Assertions.assertEquals("XR1C48", vin.getVDS()); // 车型年份 - Assertions.assertEquals(Year.of(2023), vin.defaultYear()); + Assertions.assertEquals(Year.of(2023), vin.getYear()); // OEM厂商 - Assertions.assertEquals("S", vin.oemCode()); + Assertions.assertEquals('S', vin.getOemCode()); // 生产序号 - Assertions.assertEquals("871", vin.prodNo()); + Assertions.assertEquals("871", vin.getProdNo()); } }