1. 程式人生 > >GBK與unicode轉換

GBK與unicode轉換

最近寫unicode分詞時,需要處理GBK輸入,用到GBK與Unicode之間的轉換

轉自http://www.latelee.org/programming-under-linux/gbk-to-unicode-table.html

------------------------------------------------------------------------------------------

大約大半年前完成一個向量字型檔類,使用freetype庫從向量字型檔中讀取字元輪廓,然後轉成只有0、1的緩衝區,可以使用許多場合。涉及了freetype的操作,同時還有字元編碼方面的知識。前不久,有同事反映說我提供的東西不能生成“綠”字。經測試,的確如此。查詢程式碼發現原來編碼轉換表不全面,沒有“綠”字的unicode碼。那個對應表是在網上找的,自己也沒做全面測試——我不會無聊到所有的漢字都測試一遍。
後來仔細一想,覺得有必要自己生成一個自己看得懂的查詢表,並且比較全面的。於是找啊找,不小心找到了一個專門介紹編碼的網站,找到了一個號稱是GB18030和unicode對應的文字檔案。具體地址是:

http://icu-project.org/repos/icu/data/trunk/charset/source/gb18030/gbkuni30.txt。這個網站還有其它許多有用的資料,雖然是英文的,但認真看看,十分有用。至於如何查詢,有志之士應該十分清楚,就不在此獻醜了(寫到這裡,突然想到,在許多工作時間中,許多東西都有手把手教——甚至一些簡單的東西,看來這種做法要改改了)。
為了在程式中使用那個表,於是自己寫了生成查詢表的小程式。程式很簡單,就是直接用上述地址的檔案生成一個一維陣列。網上有類似的表,有的陣列是二維的,查詢不方便。下面的程式生成的是陣列是按照GBK編碼排序的,就是說,直接用GBK的編碼查詢陣列即得到unicode碼。比如,漢字“綠”的GBK編碼是0xc2cc,則陣列的第0xc2cc偏移的值就是“綠”的unicode編碼:0x7eff。
完整程式碼如下:

#include <stdio.h> #include <stdlib.h> #include <string.h> #define ARRAY "gbkuni30" #define MAX_LEN 65535 // 2位元組最大數 static unsigned short big_buffer[MAX_LEN] = {0}; // 原始檔 #define SRC "gbkuni30.txt" // 生產的標頭檔案 #define DST "gbkuni30_gen.h" int make_charmap_gb18030() { char buffer[16] = {0}; char* p = NULL; FILE* fp_c = NULL; FILE* fp = NULL; int len = 0; int x1 = 0; int x2 = 0; int i = 0; int max_num = 0; int cnt = 0; fp = fopen(SRC, "r"); if (fp == NULL) { printf("open fileerror!!\n"); return -1; } fseek(fp, 0, SEEK_END); len = ftell(fp); fseek(fp,0,SEEK_SET); printf("file len: %d\n", len); fp_c = fopen(DST, "w+"); if (fp_c == NULL) { printf("open fileerror!!\n"); return -1; } fprintf(fp_c, "/**********************************************************************************/\n"); fprintf(fp_c, "/* GBK(GB18030) to UNICODE table, powered by LateLee */\n"); fprintf(fp_c, "/* http://www.latelee.org */\n"); fprintf(fp_c, "/* %s%s */\n", __DATE__, __TIME__); fprintf(fp_c, "/* The source file comesfrom: */\n"); fprintf(fp_c, "/*http://icu-project.org/repos/icu/data/trunk/charset/source/gb18030/gbkuni30.txt*/\n"); fprintf(fp_c, "/**********************************************************************************/\n"); fprintf(fp_c, "#ifndef__GBK2UNICODE__H\n"); fprintf(fp_c, "#define __GBK2UNICODE__H\n\n"); fprintf(fp_c, ""); fprintf(fp_c, "static unsigned short %s[] =\n{\n", ARRAY); while (fgets(buffer, 32, fp) != NULL) { sscanf(buffer, "%x:%x\n", &x1, &x2); //printf("%s",buffer); //printf("%04x %x\n",x1, x2); //fprintf(fp_c, "0x%04x,0x%x,\n", x1, x2); big_buffer[x2] = x1; if (x2 > max_num) max_num = x2; } printf("max num: %d%x\n", max_num, max_num); for (i = 0; i < max_num + 1; i++) { //printf("0x%04x\n",big_buffer[i]); fprintf(fp_c, "0x%04x,", big_buffer[i]); cnt++; if (cnt % 10 == 0) { fprintf(fp_c, " // line num %d \n", cnt / 10 - 1); } } fprintf(fp_c, "\n"); fprintf(fp_c, "};\n\n"); fprintf(fp_c, "#endif//__GBK2UNICODE__H\n"); fprintf(stdout, "Job done!\n"); fclose(fp); fclose(fp_c); return 0; }

GBK轉換成unicode碼函式如下:

int gbk_to_unicode(unsigned short int* unicode, const char* gb, int len) { int i,j; i = 0; unsigned char* gb_temp = (unsigned char *)gb; //必須轉換成無符號 for(j = 0; i < len; j++) { if (gb_temp[i] <= 0x80) { unicode[j] = gb_temp[i]; i++; } else { unsigned short int temp; temp = (gb_temp[i] << 8) + gb_temp[i+1]; unicode[j] = gbkuni30[temp]; i += 2; } } return j; }

注意上面的函式的定址方式,這裡會涉及到大小端的問題,定址方式一定要和生成的查詢表對應。這裡轉換得到的temp的值就是漢字的GBK碼,直接查詢陣列即得到unicode碼。
測試函式如下:

void main() { make_charmap_gb18030(); printf("total len:%d(%.1fKB)\n", sizeof(gbkuni30), sizeof(gbkuni30) / 1024.0); const char* p="啊"; int len = (int)strlen(p); unsigned short* unicode = new unsigned short[len]; int unicode_len = 0; unicode_len = gbk_to_unicode(unicode, p, len); for (int i = 0; i < unicode_len; i++) { printf("gbk: %02x %02x,unicode: %x\n", p[i], p[i+1], unicode[i]); } }

線上檢視編碼http://www.mytju.com/classCode/tools/encode_gb2312.asp