Foxmail 等經典軟體支援 GB/BIG5 雙內碼顯示。本文詳細記錄如何在 C++Builder 中為 TRichEdit 增加 BIG5→GB 碼表轉換功能,從碼表獲取、轉換陣列產生到即時解碼顯示完整流程。
0x81–0xFE,低位 0x40–0x7E + 0xA1–0xFECCDOS.TAB (45,840 位元組)
// TABTOHEX.cpp (Console App)
#include
#include
int main() {
FILE *tab = fopen("ccdos.tab", "rb");
FILE *hex = fopen("tab.h", "wb");
fputs("unsigned char tab[45840]={", hex);
for (int i = 0; i < 45840; i++) {
if (i % 20 == 0) fputs("\n", hex);
unsigned int ch = fgetc(tab);
fprintf(hex, "0x%x,", ch);
}
fputs("0xff};", hex);
fcloseall();
return 0;
}
編譯執行得 tab.h,含 unsigned char tab[45840] 陣列定義。
#include "tab.h" // 包含碼表陣列
void __fastcall TForm1::Button1Click(TObject *Sender) {
char *text = RichEdit1->Lines->GetText(); // 取得完整文字緩衝區
unsigned long i = 0;
while (text[i]) {
unsigned char ch1 = text[i];
if (ch1 >= 0xA1) { // 可能為 BIG5 高位元組
unsigned char ch2 = text[i+1];
unsigned long addr;
if (ch2 >= 0x40 && ch2 <= 0x7E) {
addr = ch1 * 314 + ch2 * 2 - 33010; // 區間 1 索引公式
} else if (ch2 >= 0xA1 && ch2 <= 0xFE) {
addr = ch1 * 314 + ch2 * 2 - 33078; // 區間 2 索引公式
} else {
i++; continue;
}
text[i] = tab[addr]; // GB 高位元組
text[i+1] = tab[addr+1]; // GB 低位元組
i += 2;
} else {
i++; // ASCII 直通
}
}
RichEdit1->Lines->Text = text; // 回寫解碼後文字
RichEdit1->SetFocus();
RichEdit1->SelStart = 0;
}
碼表線性排列:所有 BIG5 編碼按高位元組主序、低位元組次序展開
0x40–0x7E):63 個碼位0xA1–0xFE):94 個碼位(hi - 0xA1) * 157 + (lo - 0x40) → 化簡得 hi*314 + lo*2 - 33010(hi - 0xA1) * 157 + 63 + (lo - 0xA1) → 化簡得 hi*314 + lo*2 - 33078addr * 2 為實際位元組偏移 (程式中直接用 tab[addr] 因陣列為 unsigned char)同理製作 GB→BIG5 碼表 (窮舉 GB 編碼 → BIG5 轉換工具 → 產出陣列),邏輯對稱,索引公式依 GB 編碼結構推導。
MultiByteToWideChar/ICU 轉換,避免雙位元組編碼地獄AnsiString Big5ToGb(const AnsiString&) 介面TEncoding (CB2009+) 原生支援此碼表查表法雖屬經典,但完整展示了「編碼映射 → 線性索引 → 陣列查表 → 就地修改」的通用字碼轉換工程模式,對理解字元編碼本質極具教學價值。