資料庫欄位多為定長位元組(如 Oracle VARCHAR2(100 BYTE)),若直接用 substring(int begin, int end) 截取字元數,遇到中英文混排會導致實際位元組長度超限,寫入失敗。核心難點:中文字元在 UTF-8 佔 3 位元組,GBK 佔 2 位元組,英文僅 1 位元組,截取時不能將雙位元組字元「切半」。
byte[]public static String substringByByte(String str, int maxBytes, String charset) throws UnsupportedEncodingException {
if (str == null || str.isEmpty() || maxBytes <= 0) return str;
byte[] bytes = str.getBytes(charset);
if (bytes.length <= maxBytes) return str;
StringBuilder sb = new StringBuilder();
int count = 0;
for (char c : str.toCharArray()) {
int charBytes = String.valueOf(c).getBytes(charset).length;
if (count + charBytes > maxBytes) break;
sb.append(c);
count += charBytes;
}
return sb.toString();
}
public static String truncateRecursive(String s, int maxBytes, String charset) throws UnsupportedEncodingException {
if (s.getBytes(charset).length <= maxBytes) return s;
return truncateRecursive(s.substring(0, s.length() - 1), maxBytes, charset);
}
注意:遞歸版效能較差(重複編碼),生產環境建議用迭代版。
| 編碼 | 英文 | 中文 |
|---|---|---|
| GB2312 / GBK / GB18030 | 1 位元組 | 2 位元組 |
| UTF-8 | 1 位元組 | 3 位元組 |
| UTF-16BE / LE | 2 位元組 | 2 位元組 |
| ISO-8859-1 | 1 位元組 | 1 位元組(不可用於中文) |
public static boolean isChineseChar(char c) {
// UTF-8 下中文≥3 bytes,英文=1 byte
return String.valueOf(c).getBytes(StandardCharsets.UTF_8).length > 1;
}
按位元組截取的本質是在指定編碼下逐字元累加位元組長度。生產代碼務必:
Charset,避免平台預設編碼差異StringBuilder 迭代構建,避免遞歸/重複編碼