import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Component
public class LicensePlateExtractorUtil {
// 蓝牌正则:省份简称(1汉字) + 发牌机关代号(1字母) + 5位序号(字母/数字)
// 排除I和O避免与1和0混淆
private static final String BLUE_PLATE_REGEX = "[\\u4e00-\\u9fa5][A-Z][A-HJ-NP-Z0-9]{5}";
// 新能源车牌正则:
// 小型车:省份简称(1汉字) + 发牌机关代号(1字母,D/F) + 6位序号(前4位数字+后1位字母)
// 大型车:省份简称(1汉字) + 发牌机关代号(1字母) + 6位序号(前1位字母+后5位数字)
private static final String NEW_ENERGY_PLATE_REGEX = "[\\u4e00-\\u9fa5][A-Z][A-HJ-NP-Z0-9]{6}";
// 使馆车牌正则 (特殊车牌示例)
private static final String EMBASSY_PATTERN = "使[A-Z0-9]{6}";
// 武警车牌正则 (特殊车牌示例)
private static final String MILITARY_PATTERN = "WJ[\\u4e00-\\u9fa5]{0,1}[0-9]{5}";
// 合并正则
private static final String COMBINED_REGEX = NEW_ENERGY_PLATE_REGEX + "|" + BLUE_PLATE_REGEX + "|" + EMBASSY_PATTERN + "|" + MILITARY_PATTERN;
// 预编译正则
private static final Pattern PLATE_PATTERN = Pattern.compile(COMBINED_REGEX);
// 中国省级行政区简称集合(包括省、自治区、直辖市、特别行政区)
private static final Set<String> VALID_PROVINCE_CODES;
static {
// 初始化有效省份简称集合
VALID_PROVINCE_CODES = new HashSet<>();
// 直辖市
VALID_PROVINCE_CODES.add("京"); // 北京
VALID_PROVINCE_CODES.add("津"); // 天津
VALID_PROVINCE_CODES.add("沪"); // 上海
VALID_PROVINCE_CODES.add("渝"); // 重庆
// 省
VALID_PROVINCE_CODES.add("冀"); // 河北
VALID_PROVINCE_CODES.add("晋"); // 山西
VALID_PROVINCE_CODES.add("辽"); // 辽宁
VALID_PROVINCE_CODES.add("吉"); // 吉林
VALID_PROVINCE_CODES.add("黑"); // 黑龙江
VALID_PROVINCE_CODES.add("苏"); // 江苏
VALID_PROVINCE_CODES.add("浙"); // 浙江
VALID_PROVINCE_CODES.add("皖"); // 安徽
VALID_PROVINCE_CODES.add("闽"); // 福建
VALID_PROVINCE_CODES.add("赣"); // 江西
VALID_PROVINCE_CODES.add("鲁"); // 山东
VALID_PROVINCE_CODES.add("豫"); // 河南
VALID_PROVINCE_CODES.add("鄂"); // 湖北
VALID_PROVINCE_CODES.add("湘"); // 湖南
VALID_PROVINCE_CODES.add("粤"); // 广东
VALID_PROVINCE_CODES.add("琼"); // 海南
VALID_PROVINCE_CODES.add("川"); // 四川
VALID_PROVINCE_CODES.add("贵"); // 贵州
VALID_PROVINCE_CODES.add("云"); // 云南
VALID_PROVINCE_CODES.add("陕"); // 陕西
VALID_PROVINCE_CODES.add("甘"); // 甘肃
VALID_PROVINCE_CODES.add("青"); // 青海
VALID_PROVINCE_CODES.add("台"); // 台湾
// 自治区
VALID_PROVINCE_CODES.add("蒙"); // 内蒙古
VALID_PROVINCE_CODES.add("桂"); // 广西
VALID_PROVINCE_CODES.add("宁"); // 宁夏
VALID_PROVINCE_CODES.add("新"); // 新疆
VALID_PROVINCE_CODES.add("藏"); // 西藏
// 特别行政区
VALID_PROVINCE_CODES.add("港"); // 香港
VALID_PROVINCE_CODES.add("澳"); // 澳门
}
/**
* 从字符串中提取所有蓝牌和新能源车牌
* @param input 待提取的字符串
* @return 提取到的车牌列表,无匹配时返回空列表
*/
public static List<String> extractAllPlates(String input) {
List<String> plates = new ArrayList<>();
if (input == null || input.isEmpty()) {
return plates;
}
Matcher matcher = PLATE_PATTERN.matcher(input);
while (matcher.find()) {
String group = matcher.group();
String provinceCode = group.substring(0, 1);
if (StringUtils.equals(provinceCode,"使") || StringUtils.equals(provinceCode,"W")){
}else {
boolean validProvinceCode = isValidProvinceCode(provinceCode);
if (!validProvinceCode){
continue;
}
}
plates.add(group);
}
return plates;
}
/**
* 区分蓝牌和新能源车牌
* @param plate 车牌号码
* @return 车牌类型描述
*/
public static String getPlateType(String plate) {
if (plate == null) {
return "无效车牌";
}
if (plate.matches(BLUE_PLATE_REGEX)) {
return "蓝牌";
} else if (plate.matches(NEW_ENERGY_PLATE_REGEX)) {
return "新能源车牌";
} else if (plate.matches(EMBASSY_PATTERN)) {
return "使馆车牌";
} else if (plate.matches(MILITARY_PATTERN)) {
return "武警车牌";
} else {
return "无效车牌";
}
}
/**
* 校验省份简称是否有效
* @param code 省份简称(单个汉字)
* @return true-有效,false-无效
*/
public static boolean isValidProvinceCode(String code) {
// 校验输入是否为单个汉字
if (code == null || code.length() != 1) {
return false;
}
// 校验是否在有效集合中
return VALID_PROVINCE_CODES.contains(code);
}
public static void main(String[] args) {
String testStr = "停车场内有:京A12345(蓝牌)、粤AD12345(新能源)、沪B67890(蓝牌)、苏AF67890(新能源)、无效车牌ABC123、使123456、WJ123456、冀X12345";
// 提取车牌
List<String> plates = extractAllPlates(testStr);
System.out.println("提取到的车牌:" + JSONObject.toJSONString(plates));
for (String plate : plates) {
System.out.println(plate + "|" + getPlateType(plate));
}
}
}
代码执行结果:
提取到的车牌:["京A12345","粤AD12345","沪B67890","苏AF67890","使123456","WJ12345","冀X12345"]
京A12345|蓝牌
粤AD12345|新能源车牌
沪B67890|蓝牌
苏AF67890|新能源车牌
使123456|使馆车牌
WJ12345|武警车牌
冀X12345|蓝牌