需求:按指定字節長度截取字符串,中文字符佔 2 字節,英文佔 1 字節,**不能將中文字符截半**。本文提供基於正則識別中文、字節計數器的完整實現,並分析邊界情況與性能優化。
[\\u4e00-\\u9fa5] 判斷是否中文import java.util.Scanner;
public class ByteSubstring {
private static final String CHINESE_REGEX = "[\\u4e00-\\u9fa5]";
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("請輸入字符串:");
String input = sc.nextLine();
System.out.print("請輸入字節數:");
int byteLimit = sc.nextInt();
System.out.println("按 " + byteLimit + " 字節分段結果:");
splitByByte(input, byteLimit);
}
public static void splitByByte(String str, int limit) {
if (str == null || limit <= 0) return;
int count = 0;
StringBuilder segment = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
String chStr = String.valueOf(ch);
int byteLen = chStr.matches(CHINESE_REGEX) ? 2 : 1;
if (count + byteLen < limit) {
segment.append(ch);
count += byteLen;
} else if (count + byteLen == limit) {
segment.append(ch);
System.out.println(segment);
segment.setLength(0);
count = 0;
} else { // 超過限制
if (segment.length() > 0) System.out.println(segment);
segment.setLength(0);
segment.append(ch);
count = byteLen;
}
}
if (segment.length() > 0) System.out.println(segment);
}
}
| 輸入字符串 | 字節限制 | 輸出段落 | 說明 |
|---|---|---|---|
| 我ABC | 4 | 我AB C | 「我」(2) + A(1) + B(1) = 4 滿足 |
| 我ABC漢DEF | 6 | 我ABC 漢DE F | 第2段「漢」(2)+D(1)+E(1)=4 未滿6,但下一字符 F 會超,故換行 |
| Hello世界 | 5 | Hello 世 界 | 純英文 5 字節恰好;中文各佔 2 字節單獨成段 |
| 😀Emoji | 4 | 😀E moji | Emoji 為增補字符,Java char 視為 2 個代碼單元(4字節),邏輯視為 2 字符 |
上述代碼基於 char 遍歷,**無法正確處理增補字符**(佔 2 個 char,即 4 字節 UTF-16)。Java 8+ 正確做法:
public static void splitByByteCorrect(String str, int limit) {
int count = 0;
StringBuilder seg = new StringBuilder();
int cp;
for (int i = 0; i < str.length(); i += Character.charCount(cp)) {
cp = str.codePointAt(i);
String chStr = new String(Character.toChars(cp));
// 簡單估算:BMP 字符按編碼判斷,增補字符統計為 4 字節 (UTF-8 通常 4 字節)
int byteLen = (cp <= 0xFFFF) ? (chStr.matches(CHINESE_REGEX) ? 2 : 1) : 4;
if (count + byteLen <= limit) {
seg.append(chStr);
count += byteLen;
} else {
if (seg.length() > 0) System.out.println(seg);
seg.setLength(0);
seg.append(chStr);
count = byteLen;
}
}
if (seg.length() > 0) System.out.println(seg);
}
Pattern CHINESE_PATTERN = Pattern.compile(CHINESE_REGEX)String.matches() 隱式編譯,改用 matcher(chStr).matches()StringBuilder 批量寫入 PrintWriterbyte[] bytes = str.getBytes(StandardCharsets.UTF_8) 截取後解碼,但需處理半個字符殘留按字節截取字符串核心在於**字符級遍歷 + 字節長度累加 + 邊界判斷**。生產代碼建議封裝為工具類,支持指定編碼(UTF-8/GBK)、增補字符正確處理、流式處理大文本。