目录
4、通过判断车架号的第9位是否是正确的校验码,判断车架号vin是否正确
模拟生成新能源车辆数据
编写一个程序,每天凌晨3点模拟生成当天的新能源车辆数据(字段信息必须包含:车架号、行驶总里程、车速、车辆状态、充电状态、剩余电量SOC、SOC低报警、数据生成时间等)。
要求:1、最终部署时,要将这些数据写到第一题的HDFS中。(如果有多个组做第一题,则任选一个HDFS即可);
2、车辆数据要按天存储,数据格式是JSON格式,另外如果数据文件大于100M,则另起一个文件存。每天的数据总量不少于300M。比如假设程序是2023-01-1 03点运行,那么就将当前模拟生成的数据写入到HDFS的/can_data/2023-01-01文件夹的can-2023-01-01.json文件中,写满100M,则继续写到can-2023-01-01.json.2文件中,依次类推;
3、每天模拟生成的车辆数据中,必须至少包含20辆车的数据,即要含有20个车架号(一个车架号表示一辆车,用字符串表示);
4、每天生成的数据中要有少量(20条左右)重复数据(所有字段都相同的两条数据则认为是重复数据),且同一辆车的两条数据的数据生成时间间隔两秒;
5、每天生成的数据中要混有少量前几天的数据(即数据生成时间不是当天,而是前几天的)。
二.随机生成车架号
1、车架号的组成部分
(1)第1位:代表出厂国家/地区
地理区域的分配规则如下:1-5为北美,6-7为大洋洲,8、9和0为南美洲,A-H为非洲,J-R为亚洲,S-Z为欧洲。具体如下:
(2)第2位:代表汽车制造商代码
全球常见汽车制造商代码表格如下:
(3)第3位:车系代码
第4~8位:描述车辆特征
这几位,不同的厂商,字符的解析意思不尽相同。一汽奥迪的如下:
(4)第4位:排量或安全保护装置
A-安全带;B-安全带+安全气囊;2-1.4T;3-2.0T;4-2.4;5-2.5、2.8;6-3.0T...
(5)第5位:车身类型
A-四门三厢、B-四门两厢、C-四门方背
(6)第6位:发动机变速箱
1-手动汽油、2-自动汽油、3-手动柴油、4-自动柴油
(7)第7-8位:车型代码
(8)第9位:校验码
第九为实校验码,只能是数字0-9或X,它是由其他16位字码对应数值乘以其所位置权数的和除以11所得的余数;当余数为0-9时候,余数就是检验数字;当余数为10时,X为检验代码。校验码的目的就是核对数字,检验VIN填写是否正确,并能防止假冒产品。
数字及英文字母对应值:
VIN码位置对应的加权系数:
(9)第10位:出厂年份
(10)第11位:车辆组装地(装配厂)
(11)第12~17位:出厂顺序代码
这六位数由厂家自行决定第12-13代码可由0-9和A-Z(除'I'、'O'、'Q'外);第14-17,这最后四位则必须也只能为0-9的数字。
以上车架号解析转载于:汽车车架号怎么看? - Do it的回答 - 知乎 https://www.zhihu.com/question/302148790/answer/860621121
2、生成车架号可能需要的字符
/**车架号地区代码数组*/
public static final String[] areaArray = new String[]{"1", "2", "3", "6", "9", "J", "K", "L", "R", "S", "T", "V", "W", "Y", "Z", "G"};
/**车架号中可能出现的字符数组*/
public static final String[] charArray = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "V", "W", "X", "Y"};
/**车架号校验位计算数组*/
public static final char[][] KVMACTHUP = new char[][]{{'A', 1}, {'B', 2}, {'C', 3}, {'D', 4}, {'E', 5}, {'F', 6},{'G', 7}, {'H', 8}, {'I', 0}, {'J', 1}, {'K', 2}, {'L', 3},{'M', 4}, {'N', 5}, {'O', 0}, {'P', 7}, {'Q', 8}, {'R', 9}, {'S', 2}, {'T', 3}, {'U', 4}, {'V', 5}, {'W', 6}, {'X', 7},{'Y', 8}, {'Z', 9}};
/**车架号数据加权数组*/
public static final int[] WEIGHTVALUE = new int[]{8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2};
public static final String[] strYear = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ,"G", "H" ,"J" ,"K" ,"L" ,"M" ,"N" ,"P" ,"R" ,"S" ,"T" ,"V" ,"W" ,"X" ,"Y"};
/**出厂顺序代码(第12~13位)*/
public static final String[] strCode = new String[]{"0","1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ,"G", "H" ,"J" ,"K" ,"L" ,"M" ,"N" ,"P" ,"R" ,"S" ,"T" ,"V" ,"W" ,"X" ,"Y"};
/**出厂顺序代码(第14~17位)*/
public static final String[] strCodeNo = new String[]{"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
3、计算校验码
校验码,只能是数字0-9或X,它是由其他16位字码对应数值乘以其所位置权数的和除以11所得的余数;当余数为0-9时候,余数就是检验数字;当余数为10时,X为检验代码。
/**
* 计算车架号的校验位
* @return
*/
public static String getIsuredCode(String vin) {
char[] Vin = vin.toCharArray();
int sum = 0,tempValue = 0;
char temp;
for (int i = 0; i < 17; i++) {
if (Vin[i] >= 'a' && Vin[i] <= 'z') {
temp = (char) (Vin[i] - 32);
} else if ((Vin[i] >= 'A') && (Vin[i] <= 'Z')) {
temp = Vin[i];
} else if ((Vin[i] >= '0') && (Vin[i] <= '9')) {
tempValue = Integer.parseInt(String.valueOf(Vin[i]));
temp = Vin[i];
} else {
return "ERROR";
}
if ((temp >= 'A') && (temp <= 'Z')) {
for (int j = 0; j < 26; j++) {
if (temp == KVMACTHUP[j][0]) {
tempValue = (int) KVMACTHUP[j][1];
}
}
}
sum += tempValue * WEIGHTVALUE[i];
}
int reslt = sum % 11;
if (reslt != 10) {
return String.valueOf(reslt);
} else {
return "X";
}
}
4、通过判断车架号的第9位是否是正确的校验码,判断车架号vin是否正确
/**
* 判断vin是否正确
* @param vin
* @return
*/
public static boolean isVin(String vin) {
String isuredCode = getIsuredCode(vin);
if (vin.substring(8, 9).equals(isuredCode)) {
return true;
} else {
return false;
}
}
5、生成随机车辆特征
/**
* 生成随机车辆特征
*
* @return
*/
public static String prepareBeforeStr() {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("LFV");
for (int i = 0; i < 5; i++) {
stringBuffer.append(getRandomChar(areaArray));
}
return stringBuffer.toString();
}
6、生成随机年份代码
/**
* 生成随机年份代码
*
* @return
*/
public static String prepareAfterStr() {
StringBuilder stringBuffer = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 1; i++) {
stringBuffer.append(strYear[random.nextInt(strYear.length)]);
}
stringBuffer.append(prepareNo());
return stringBuffer.toString();
}
7、 生成随机的生产序号
第11位:车辆组装地(装配厂),第12-13代码可由0-9和A-Z(除'I'、'O'、'Q'外);第14-17,这最后四位则必须也只能为0-9的数字。
/**
* 生成随机的生产序号
* @return
*/
public static String prepareNo(){
Random random = new Random();
StringBuilder numStrBuff = new StringBuilder();
for(int i=0;i<3;i++){
numStrBuff.append(strCode[random.nextInt(strCode.length)]);//第11~13位车架号
}
for (int i=0;i<4;i++){
numStrBuff.append(strCodeNo[random.nextInt(strCodeNo.length)]);//第14~17位车架号
}
return numStrBuff.toString();
}
8、拼接车架号
/**
* 拼接车架号
*
* @param beforeStr
* @param afterStr
* @return
*/
public static String spellVin(String beforeStr, String afterStr) {
StringBuffer vinBuffer = new StringBuffer();
String preVin = vinBuffer.append(beforeStr).append("X").append(afterStr).toString();
String isuredCode = getIsuredCode(preVin);
String vin = new StringBuffer(beforeStr).append(isuredCode).append(afterStr).toString();
if (isVin(vin)) {
return vin;
} else {
return spellVin(beforeStr, afterStr);
}
}
9、返回随机字符
/**
* 返回随机字符
* @return
*/
public static String getRandomChar(Object array[]) {
Random random = new Random();
return charArray[random.nextInt(array.length)];
}
10、获取随机车架号
public static String getRandomVin() {
String beforeStr = prepareBeforeStr();
String afterStr = prepareAfterStr();
String vin = spellVin(beforeStr, afterStr);
return vin;
}
11、获取对应数量的随机车架号
public static List<String> getVinList(int num){
List<String> vinList = new ArrayList<String>();
for(int i =0;i<num;i++){
vinList.add(getRandomVin());
}
return vinList;
}
12、随机获取重复的车架号
public static List<String> VinList(List<String> vinlist,int num){
List<String> list = new ArrayList<String>();
Random random = new Random();
for (int i =0;i<num;i++){
list.add(vinlist.get(random.nextInt(vinlist.size())));
}
return list;
}
三、随机生成车架号代码整理
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Vin {
/**车架号地区代码数组*/
public static final String[] areaArray = new String[]{"1", "2", "3", "6", "9", "J", "K", "L", "R", "S", "T", "V", "W", "Y", "Z", "G"};
/**车架号中可能出现的字符数组*/
public static final String[] charArray = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "V", "W", "X", "Y"};
/**车架号校验位计算数组*/
public static final char[][] KVMACTHUP = new char[][]{{'A', 1}, {'B', 2}, {'C', 3}, {'D', 4}, {'E', 5}, {'F', 6},{'G', 7}, {'H', 8}, {'I', 0}, {'J', 1}, {'K', 2}, {'L', 3},{'M', 4}, {'N', 5}, {'O', 0}, {'P', 7}, {'Q', 8}, {'R', 9}, {'S', 2}, {'T', 3}, {'U', 4}, {'V', 5}, {'W', 6}, {'X', 7},{'Y', 8}, {'Z', 9}};
/**车架号数据加权数组*/
public static final int[] WEIGHTVALUE = new int[]{8, 7, 6, 5, 4, 3, 2, 10, 0, 9, 8, 7, 6, 5, 4, 3, 2};
/**生产年份代码(第12~13位)*/
public static final String[] strYear = new String[]{"1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ,"G", "H" ,"J" ,"K" ,"L" ,"M" ,"N" ,"P" ,"R" ,"S" ,"T" ,"V" ,"W" ,"X" ,"Y"};
/**出厂顺序代码(第12~13位)*/
public static final String[] strCode = new String[]{"0","1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ,"G", "H" ,"J" ,"K" ,"L" ,"M" ,"N" ,"P" ,"R" ,"S" ,"T" ,"V" ,"W" ,"X" ,"Y"};
/**出厂顺序代码(第14~17位)*/
public static final String[] strCodeNo = new String[]{"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
/**
* 计算车架号的校验位
* @return
*/
public static String getIsuredCode(String vin) {
char[] Vin = vin.toCharArray();
int sum = 0,tempValue = 0;
char temp;
for (int i = 0; i < 17; i++) {
if (Vin[i] >= 'a' && Vin[i] <= 'z') {
temp = (char) (Vin[i] - 32);
} else if ((Vin[i] >= 'A') && (Vin[i] <= 'Z')) {
temp = Vin[i];
} else if ((Vin[i] >= '0') && (Vin[i] <= '9')) {
tempValue = Integer.parseInt(String.valueOf(Vin[i]));
temp = Vin[i];
} else {
return "ERROR";
}
if ((temp >= 'A') && (temp <= 'Z')) {
for (int j = 0; j < 26; j++) {
if (temp == KVMACTHUP[j][0]) {
tempValue = (int) KVMACTHUP[j][1];
}
}
}
sum += tempValue * WEIGHTVALUE[i];
}
int reslt = sum % 11;
if (reslt != 10) {
return String.valueOf(reslt);
} else {
return "X";
}
}
/**
* 判断vin是否正确
* @param vin
* @return
*/
public static boolean isVin(String vin) {
String isuredCode = getIsuredCode(vin);
if (vin.substring(8, 9).equals(isuredCode)) {
return true;
} else {
return false;
}
}
/**
* 拼接车架号
*
* @param beforeStr
* @param afterStr
* @return
*/
public static String spellVin(String beforeStr, String afterStr) {
StringBuffer vinBuffer = new StringBuffer();
String preVin = vinBuffer.append(beforeStr).append("X").append(afterStr).toString();
String isuredCode = getIsuredCode(preVin);
String vin = new StringBuffer(beforeStr).append(isuredCode).append(afterStr).toString();
if (isVin(vin)) {
return vin;
} else {
return spellVin(beforeStr, afterStr);
}
}
/**
* 生成随机车辆特征
*
* @return
*/
public static String prepareBeforeStr() {
StringBuilder stringBuffer = new StringBuilder();
stringBuffer.append("LFV");
for (int i = 0; i < 5; i++) {
stringBuffer.append(getRandomChar(areaArray));
}
return stringBuffer.toString();
}
/**
* 生成随机年份
*
* @return
*/
public static String prepareAfterStr() {
StringBuilder stringBuffer = new StringBuilder();
Random random = new Random();
for (int i = 0; i < 1; i++) {
stringBuffer.append(strYear[random.nextInt(strYear.length)]);
}
stringBuffer.append(prepareNo());
return stringBuffer.toString();
}
/**
* 生成随机的生产序号
* @return
*/
public static String prepareNo(){
Random random = new Random();
StringBuilder numStrBuff = new StringBuilder();
for(int i=0;i<3;i++){
numStrBuff.append(strCode[random.nextInt(strCode.length)]);//第11~13位车架号
}
for (int i=0;i<4;i++){
numStrBuff.append(strCodeNo[random.nextInt(strCodeNo.length)]);//第14~17位车架号
}
return numStrBuff.toString();
}
/**
* 返回随机字符
* @return
*/
public static String getRandomChar(Object array[]) {
Random random = new Random();
return charArray[random.nextInt(array.length)];
}
/**
* 获取随机的车架号
* @return
*/
public static String getRandomVin() {
String beforeStr = prepareBeforeStr();
String afterStr = prepareAfterStr();
String vin = spellVin(beforeStr, afterStr);
return vin;
}
/**
* 获取对应数量的随机车架号
* @param num
* @return
*/
public static List<String> getVinList(int num){
List<String> vinList = new ArrayList<String>();
for(int i =0;i<num;i++){
vinList.add(getRandomVin());
}
return vinList;
}
public static List<String> VinList(List<String> vinlist,int num){
List<String> list = new ArrayList<String>();
Random random = new Random();
for (int i =0;i<num;i++){
list.add(vinlist.get(random.nextInt(vinlist.size())));
}
return list;
}
}