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());
}
}