String Bytes 問題

記錄一下維護程式遇到的一個 bug

資料庫欄位是 Oracle VARCHAR2(byte)
但程式並沒有校驗傳入參數的長度
而是要在寫入 DB 前才截斷超過的部分
方法如下

public static String substringByBytes(String string, int length) {
    if (string == null)
        return null;
    return new String(string.getBytes(), 0, length);
}

但結果卻不如預期

String cuttedString = substringByBytes("壹貳參肆", 11);
System.out.println(cuttedString); //壹貳參�
System.out.println(cuttedString.getBytes().length); //12

字串「壹貳參肆」在 UTF8 編碼下共 12 bytes
若將其擷取為 11 bytes
最後一個字元「肆」會從 3 bytes 被切成 2 bytes
結果出現的奇怪字元本身仍是佔 3 bytes
因此長度並未減少

String cuttedString = substringByBytes("壹貳參abc", 11);
System.out.println(cuttedString); //壹貳參ab
System.out.println(cuttedString.getBytes().length); //11

可以對比
若非 UTF8 就是正常的
因此必須逐個字元計算 bytes 長度
修改後如下

public static String substringByBytesWithCompleteChars(String string, int length, Charset charset) {
    if (string == null)
        return null;

    if (string.getBytes(charset).length <= length)
        return string;

    StringBuilder result = new StringBuilder();
    int count = 0;

    for (String str : string.split("")) {
        count += str.getBytes(charset).length;
        if (count > length)
            break;
        result.append(str);
    }

    return result.toString();
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *