繼GDAL庫、PROJ庫、HDF5庫、TINYXML庫之後,手上進行的項目又讓我碰到了ICONV庫。之前花了2天時間沒有搞定,在甲方一直催促下,今天又撿起來搞搞,搞了一天終於搞定了。相關心得記錄如下:
ICONV庫的主要作用是進行各個國家不同編碼方式之間的轉換。只要支持的有:Unicode[utf8、utf16等]、中國標準[GBK、GB18030、BIG5、EUC-CN等]、歐洲標準[ASCLL、CP、Mac等]。我這個項目中涉及到的就是utf8與GBK之間的轉換。
早期的ICONV庫是同時發佈LINUX和WINDOWS的版本的,在1.11版本之後不再對WINDOWS進行支持,目前最新的版本爲2011年發佈的1.14。
第一步:
在linux下面編譯的命令很簡單:
@./configure
@make
@make install
三條命令執行完成之後在/usr/local/include下面會出現三個.h文件。在/usr/local/lib下面會出現11個文件(.a及其.so)。
第二步:
在編寫轉換程序之前有必要先看看系統的編碼方式是什麼。命令爲@locale。
LANG=en_US.UTF-8
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX "
LC_MESSAGES="POSIX "
LC_PAPER="POSIX "
LC_NAME="POSIX "
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX "
LC_MEASUREMENT="POSIX "
LC_IDENTIFICATION="POSIX "
LC_ALL="POSIX "
上面的信息顯示當前系統的編碼方式爲UTF8,爲了與甲方服務器一致,修改成GBK。
@vi /etc/profile
在末尾添加2行:
export LC_ALL="zh_CN.GBK"
export LANG="zh_CN.GBK"
@reboot
@locale
LANG=zh_CN.GBK
LC_CTYPE="zh_CN.GBK
LC_NUMERIC="zh_CN.GBK "
LC_TIME="zh_CN.GBK "
LC_COLLATE="zh_CN.GBK
LC_MONETARY="zh_CN.GBK "
LC_MESSAGES="zh_CN.GBK "
LC_PAPER="zh_CN.GBK "
LC_NAME="zh_CN.GBK "
LC_ADDRESS="zh_CN.GBK "
LC_TELEPHONE="zh_CN.GBK "
LC_MEASUREMENT="zh_CN.GBK "
LC_IDENTIFICATION="zh_CN.GBK "
LC_ALL=zh_CN.GBK
上面的信息表明系統的編碼方式已經修改成功。
第三步:
設置鏈接庫的環境變量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
第四步:
在cpp文件中包含頭文件
#include <iconv.h>
第五步:
編寫轉換函數
bool ChangeCodeToGBK(char* szInstr,int in,char* szOutstr,int out)
{
iconv_t conveter=iconv_open("GBK","UTF-8");
//iconv_open函數第一個參數爲ToEncoding,第二個參數爲FromEncoding
memset(szOutstr,0,out);
char **source=&szInstr;
char **dest=&szOutstr;
iconv(conveter,(char **)source,(size_t *)&in,(char **)dest,(size_t *)&out);
iconv_close(conveter);
return 0;
}
bool ChangeCodeToUTF8(char* szInstr,int in,char* szOutstr,int out)
{
iconv_t conveter=iconv_open("UTF-8","GBK");
memset(szOutstr,0,out);
char **source=&szInstr;
char **dest=&szOutstr;
iconv(conveter,(char **)source,(size_t *)&in,(char **)dest,(size_t *)&out);
iconv_close(conveter);
return 0;
}
第六步:
主函數調用示範
const char * pathMetaData = NULL;
//讀取UTF8格式的字符串,存入pathMetaData數組中。
printf("Input IRS Metadata path = %s \n\n",pathMetaData);
char strcopy[256];
memset(strcopy,0,256);
char szgbk[256];
memset(szgbk,0,256);
strcpy(strcopy,pathMetaData);
ChangeCodeToGBK(strcopy,strlen(strcopy),szgbk,256);
strcpy(const_cast<char*>(pathMetaData),szgbk);
printf("Encoding changed!\nInput IRS Metadata path = %s \n\n",pathMetaData);
第七步:
添加一個判斷函數IsTextUTF8( char *lpstrInputStream, int iLen )
bool IsTextUTF8( char *lpstrInputStream, int iLen )
{
int i;
unsigned long cOctets; // octets to go in this UTF-8 encoded character
unsigned char chr;
bool bAllAscii= true;
cOctets= 0;
for( i=0; i < iLen; i++ )
{
chr= *(lpstrInputStream+i);
if( (chr&0x80) != 0 ) bAllAscii= false;
if( cOctets == 0 )
{
// 7 bit ascii after 7 bit ascii is just fine. Handle start of encoding case.
if( chr >= 0x80 )
{
// count of the leading 1 bits is the number of characters encoded
do
{
chr <<= 1;
cOctets++;
}
while( (chr&0x80) != 0 );
cOctets--; // count includes this character
if( cOctets == 0 ) return false; // must start with 11xxxxxx
}
}
else
{
// non-leading bytes must start as 10xxxxxx
if( (chr&0xC0) != 0x80 )
{
return false;
}
cOctets--; // processed another octet in encoding
}
}
// End of text. Check for consistency.
if( cOctets > 0 ) // anything left over at the end is an error
{
return false;
}
if( bAllAscii ) // Not utf-8 if all ascii. Forces caller to use code pages for conversion
{
return false;
}
return true;
}