package jnpf.elnService.impl; import com.huaban.analysis.jieba.JiebaSegmenter; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; import java.util.Locale; import java.util.function.Supplier; public final class ElnFieldCodeGenerator { private static final int MAX_CODE_LENGTH = 80; private static final int DEFAULT_SUFFIX_LENGTH = 6; private final Supplier suffixSupplier; private final int suffixLength; public ElnFieldCodeGenerator(Supplier suffixSupplier) { this(suffixSupplier, DEFAULT_SUFFIX_LENGTH); } public ElnFieldCodeGenerator(Supplier suffixSupplier, int suffixLength) { this.suffixSupplier = suffixSupplier; if (suffixLength < 1) { throw new IllegalArgumentException("字段编码随机后缀长度必须大于 0"); } this.suffixLength = suffixLength; } public String generate(String label, boolean templateField) { return buildCode(normalizeSegmented(label), "field", "f", templateField); } public String generate(String label, String fallback, String numericPrefix) { return generate(label, fallback, numericPrefix, false); } public String generateSegmented(String label, String fallback, String numericPrefix) { return buildCode(normalizeSegmented(label), fallback, numericPrefix, false); } public static String suggestSegmentedCode(String text) { String normalized = normalizeSegmented(text); if (normalized.length() <= MAX_CODE_LENGTH) { return normalized; } int segmentBoundary = normalized.lastIndexOf('_', MAX_CODE_LENGTH); if (segmentBoundary > 0) { return normalized.substring(0, segmentBoundary); } return trimTrailingUnderscore(normalized.substring(0, MAX_CODE_LENGTH)); } private String generate(String label, String fallback, String numericPrefix, boolean alwaysPrefix) { return buildCode(normalize(label), fallback, numericPrefix, alwaysPrefix); } private String buildCode(String normalizedLabel, String fallback, String numericPrefix, boolean alwaysPrefix) { String base = normalizedLabel; if (base.isEmpty()) { base = fallback; } if (Character.isDigit(base.charAt(0))) { base = numericPrefix + "_" + base; } if (alwaysPrefix) { base = "p_" + base; } String suffix = normalizeSuffix(suffixSupplier.get()); int baseLimit = MAX_CODE_LENGTH - suffixLength - 1; if (base.length() > baseLimit) { base = trimTrailingUnderscore(base.substring(0, baseLimit)); } return base + "_" + suffix; } private static String normalizeSegmented(String value) { if (value == null) { return ""; } StringBuilder result = new StringBuilder(); for (String segment : SegmenterHolder.INSTANCE.sentenceProcess(value)) { String normalized = normalizeWord(segment); if (!normalized.isEmpty()) { appendSeparator(result); result.append(normalized); } } return trimTrailingUnderscore(result.toString()).replaceAll("_+", "_"); } private static String normalizeWord(String value) { HanyuPinyinOutputFormat format = pinyinFormat(); StringBuilder result = new StringBuilder(); for (char character : value.toCharArray()) { if (character < 128 && Character.isLetterOrDigit(character)) { result.append(Character.toLowerCase(character)); continue; } String[] pinyin = toPinyin(character, format); if (pinyin != null && pinyin.length > 0) { result.append(pinyin[0]); } } return result.toString(); } private static String normalize(String value) { if (value == null) { return ""; } HanyuPinyinOutputFormat format = pinyinFormat(); StringBuilder result = new StringBuilder(); for (char character : value.toCharArray()) { if (character < 128 && Character.isLetterOrDigit(character)) { result.append(Character.toLowerCase(character)); continue; } String[] pinyin = toPinyin(character, format); if (pinyin != null && pinyin.length > 0) { appendSeparator(result); result.append(pinyin[0]); appendSeparator(result); } else { appendSeparator(result); } } return trimTrailingUnderscore(result.toString()).replaceAll("_+", "_"); } private static HanyuPinyinOutputFormat pinyinFormat() { HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); format.setCaseType(HanyuPinyinCaseType.LOWERCASE); format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); format.setVCharType(HanyuPinyinVCharType.WITH_V); return format; } private static String[] toPinyin(char character, HanyuPinyinOutputFormat format) { try { return PinyinHelper.toHanyuPinyinStringArray(character, format); } catch (BadHanyuPinyinOutputFormatCombination ignored) { // format is fixed and valid return null; } } private String normalizeSuffix(String suffix) { String value = suffix == null ? "" : suffix.toLowerCase(Locale.ROOT) .replaceAll("[^a-z0-9]", ""); if (value.length() < suffixLength) { throw new IllegalStateException("字段编码随机后缀必须至少包含 " + suffixLength + " 位字母或数字"); } return value.substring(0, suffixLength); } private static void appendSeparator(StringBuilder value) { if (value.length() > 0 && value.charAt(value.length() - 1) != '_') { value.append('_'); } } private static String trimTrailingUnderscore(String value) { int end = value.length(); while (end > 0 && value.charAt(end - 1) == '_') { end--; } return value.substring(0, end); } private static final class SegmenterHolder { private static final JiebaSegmenter INSTANCE = new JiebaSegmenter(); } }