背景:
linux下的C可执行程序从数据库oracle里读取中文,并将数据通过报文方式送出。
参考:http://www.ibm.com/developerworks/cn/linux/i18n/unicode/linuni/
明确问题:
1)可执行程序本身生成汉字,并进行传送时,字符的编码格式从何处决定?
2)可执行程序本身不生成汉字, 只是从别处取汉字(如从数据库),此时取汉字所进行的编码格式?
--------------------------------------------------------------------------------------------
根据问题1:
由下面的一段话可以看出,可执行程序如是本身生成汉字, 其编码方式会受以下环境变量影响。 (实验证明,此观点有误,详细可以查看后面实例,具体什么原因不清楚。汉字展示生环境变理有关,但生成编码与环境变理无关)
在Linux中通过locale来设置程序运行的不同语言环境,locale由ANSI C提供支持。locale的命名规则为<语言>_<地区>.<字符集编码>,如zh_CN.UTF-8,zh代表中文,CN代表大陆地区,UTF-8表示字符集。在locale环境中,有一组变量,代表国际化环境中的不同设置:
1. LC_COLLATE
定义该环境的排序和比较规则
2. LC_CTYPE
用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等。是最重要的一个环境变量。
3. LC_MONETARY
货币格式
4. LC_NUMERIC
非货币的数字显示格式
5. LC_TIME
时间和日期格式
6. LC_MESSAGES
提示信息的语言。另外还有一个LANGUAGE参数,它与LC_MESSAGES相似,但如果该参数一旦设置,则LC_MESSAGES参数就会失效。LANGUAGE参数可同时设置多种语言信息,如LANGUANE="zh_CN.GB18030:zh_CN.GB2312:zh_CN"。
7. LANG
LC_*的默认值,是最低级别的设置,如果LC_*没有设置,则使用该值。类似于 LC_ALL。
8. LC_ALL
它是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
根据问题2:
由下面的说明,可以得到此处取数据时是有对数据进行字符集转换操作。
NLS_LANG 字符集反映的是客户端操作系统的字符集设置。所以,正确设置 NLS_LANG 可以允许从客户端操作系统字符集到数据库字符集的正确转换。当两端使用同样的字符集设置时, Oracle 会认为数据的发送或接收使用相同的字符集,从而不会发生字符集校验或转换。如果客户端字符集与数据库字符集不一致将会导致乱码,此时转换是有必要的。
---------------------------------------------------------------------------------------------
结论:
1:当程序本身不生产汉字时, 只进行获取时, 由获取处决定编码格式。
说明: GBK 二字节表示一个汉字,UTF-8 三字节表示一个汉字。
待编码汉字:卡友支付-武汉长江航证电子商务有一有限公
GBK
卡BFA8友D3D1支D6A7付B8B6武CEE4汉BABA长B3A4江BDAD航BABD证D6A4电B5E7子D7D3商C9CC务CEF1有D3D0一D2BB有D3D0限CFDE公B9AB
UTF-8
卡%E5%8D%A1友%E5%8F%8B支%E6%94%AF付%E4%BB%98武%E6%AD%A6汉%E6%B1%89长%E9%95%BF江%E6%B1%9F航%E8%88%AA证%E8%AF%81电%E7%94%B5子%E5%AD%90商%E5%95%86务%E5%8A%A1有%E6%9C%89一%E4%B8%80有%E6%9C%89限%E9%99%90公
当对方系统你需以某种字符编码进行数据传送时,需要明确:
1:本程序的字符编码的生成编码(而不是终端查看的情形,可以打出字符的内码进行分析)
2:应用iconv函数族编程实现字符集编码转换。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
实例说明
实例1:汉字字符集内码生成是否与环境变量有关? 结果无关。
实例2:汉字字符集内友生成是否与源文件编码格式有关?结查有关。
--------------------------------------------------------------------------------------------------------
实例1:(GBK纺码)
/***************************************************************************** * 文件 名:checkiconv.c * 版 本: 1.00 * 运行环境: linux. * 功 能: * 历史记录: 日 期 作 者 备 注 *----------------------------------------------------------------------------* * 2014-6-30 mengfh 创建. * *----------------------------------------------------------------------------* * All rights reserved. Copyright (C) 2014-2020. ******************************************************************************/ #include<stdio.h> #include<string.h> #include<stdlib.h> #include <iconv.h> //作用,同时进行定义数组的大小,同时做为编码转换出时字节长度 #define OUTLEN 255 int main() { // char *in_utf8 = "姝e?ㄥ??瑁?"; // char *in_gb2312 = "正在安装"; //测试数据 ,可以通过工具查看相关的汉字的字符编码http://bm.kdd.cc/index.asp //UTF-8 友支:%E5%8D%A1友%E5%8F%8B支 //GBK 友支:BFA8友D3D1支 char *in_utf8 = "\xe5\x8d\xa1\xe5\x8f\x8b"; char *in_gb2312 = "\xbf\xa8\xd3\xd1"; char out[OUTLEN]; char tmp[OUTLEN]; int rc=0; int i=0; //unicode码转为gb2312码 rc = u2g(in_utf8, strlen(in_utf8), out, OUTLEN); printf("unicode-->gb2312 out=%s\n", out); //gb2312码转为unicode码 rc = g2u(in_gb2312, strlen(in_gb2312), out, OUTLEN); printf("gb2312-->unicode out=%s\n", out); fprintf(stderr, "此时的out为乱码,请看下面十六进制输出数据:\n"); for(i = 0 ;i <OUTLEN ; i ++) { if( out[i]== '\0') { fprintf(stderr, "\n"); break; } fprintf(stderr," %02X", out[i]); } //again memset(tmp, 0 ,sizeof(tmp)); memcpy(tmp, out, OUTLEN); rc = u2g(tmp, strlen(tmp), out, OUTLEN); printf("Again !\nunicode-->gb2312 out=%s\n", out); return 0 ; } //代码转换:从一种编码转为另一种编码 int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen) { iconv_t cd; int rc; char **pin = &inbuf; char **pout = &outbuf; cd = iconv_open(to_charset, from_charset); if (cd == 0) return -1; memset(outbuf, 0, outlen); if (iconv(cd, pin, &inlen, pout, &outlen) == -1) return -1; iconv_close(cd); return 0; } //UNICODE码转为GB2312码 int u2g(char *inbuf, int inlen, char *outbuf, int outlen) { return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen); } //GB2312码转为UNICODE码 int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen) { return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen); }
测试环境(UTF-8) :
localhost@/home/term/mengfh/checkfun>>locale
LANG=en_US.UTF-8
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=zh_CN.UTF-8
远程客户端的字符编码也需要调成UTF-8 ——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
unicode-->gb2312 out=¿¨ԑ
gb2312-->unicode out=卡友 (完美的打出)
´̊±µïutΪÒ룬ȫ¿´ЂĦʮ¹½狤³뽾ݣº
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=¿¨ԑ
远程客户端的字符编码也需要调成GBK——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
localhost@/home/term>>locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or directory
LANG=en_US.ZHS16GBK
LC_CTYPE="en_US.ZHS16GBK"
LC_NUMERIC="en_US.ZHS16GBK"
LC_TIME="en_US.ZHS16GBK"
LC_COLLATE="en_US.ZHS16GBK"
LC_MONETARY="en_US.ZHS16GBK"
LC_MESSAGES="en_US.ZHS16GBK"
LC_PAPER="en_US.ZHS16GBK"
LC_NAME="en_US.ZHS16GBK"
LC_ADDRESS="en_US.ZHS16GBK"
LC_TELEPHONE="en_US.ZHS16GBK"
LC_MEASUREMENT="en_US.ZHS16GBK"
LC_IDENTIFICATION="en_US.ZHS16GBK"
LC_ALL=
远程客户端的字符编码也需要调成GBK——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
远程客户端的字符编码也需要调成UTF-8 ——打出结果:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=¿¨ԑ
gb2312-->unicode out=卡友
´̊±µïutΪÒ룬ȫ¿´ЂĦʮ¹½狤³뽾ݣº
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=¿¨ԑ
得出结论:
程序自己生产汉字时:字符编码与环境变量没有关系,只关系到显示。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
实例2:
/***************************************************************************** * 文件 名:checkiconv.c * 版 本: 1.00 * 运行环境: linux. * 功 能: * 历史记录: 日 期 作 者 备 注 *----------------------------------------------------------------------------* * 2014-6-30 mengfh 创建. * *----------------------------------------------------------------------------* * All rights reserved. Copyright (C) 2014-2020. ******************************************************************************/ #include<stdio.h> #include<string.h> #include<stdlib.h> #include <iconv.h> //作用,同时进行定义数组的大小,同时做为编码转换出时字节长度 #define OUTLEN 255 int main() { // char *in_utf8 = "姝e?ㄥ??瑁?"; // char *in_gb2312 = "正在安装"; //测试数据 ,可以通过工具查看相关的汉字的字符编码http://bm.kdd.cc/index.asp //UTF-8 友支:%E5%8D%A1卡%E5%8F%8B友 //GBK 友支:BFA8卡D3D1友 char *str="卡友"; char *in_utf8 = "\xe5\x8d\xa1\xe5\x8f\x8b"; char *in_gb2312 = "\xbf\xa8\xd3\xd1"; char out[OUTLEN]; char tmp[OUTLEN]; int rc=0; int i=0; memset(tmp, 0 ,sizeof(tmp)); memcpy(tmp, str, strlen(str)); for(i = 0 ;i <OUTLEN ; i ++) { if( tmp[i]== '\0') { fprintf(stderr, "\n"); break; } fprintf(stderr," [%d]%02X",i, tmp[i]); } //unicode码转为gb2312码 rc = u2g(in_utf8, strlen(in_utf8), out, OUTLEN); printf("unicode-->gb2312 out=%s\n", out); //gb2312码转为unicode码 rc = g2u(in_gb2312, strlen(in_gb2312), out, OUTLEN); printf("gb2312-->unicode out=%s\n", out); fprintf(stderr, "文件以GBK进行编码此时的out为乱码,请看下面十六进制输出数据:\n"); for(i = 0 ;i <OUTLEN ; i ++) { if( out[i]== '\0') { fprintf(stderr, "\n"); break; } fprintf(stderr," %02X", out[i]); } //again memset(tmp, 0 ,sizeof(tmp)); memcpy(tmp, out, OUTLEN); rc = u2g(tmp, strlen(tmp), out, OUTLEN); printf("Again !\nunicode-->gb2312 out=%s\n", out); return 0 ; } //代码转换:从一种编码转为另一种编码 int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen) { iconv_t cd; int rc; char **pin = &inbuf; char **pout = &outbuf; cd = iconv_open(to_charset, from_charset); if (cd == 0) return -1; memset(outbuf, 0, outlen); if (iconv(cd, pin, &inlen, pout, &outlen) == -1) return -1; iconv_close(cd); return 0; } //UNICODE码转为GB2312码 int u2g(char *inbuf, int inlen, char *outbuf, int outlen) { return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen); } //GB2312码转为UNICODE码 int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen) { return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen); }
源代码以GBK进行编码时:
localhost@/home/term/mengfh/checkfun>>./checkiconv
[0]FFFFFFBF [1]FFFFFFA8 [2]FFFFFFD3 [3]FFFFFFD1
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
此时的out为乱码,请看下面十六进制输出数据:
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
源代码以utf-8进行编码时:
localhost@/home/term/mengfh/checkfun>>./checkiconv2
[0]FFFFFFE5 [1]FFFFFF8D [2]FFFFFFA1 [3]FFFFFFE5 [4]FFFFFF8F [5]FFFFFF8B
unicode-->gb2312 out=卡友
gb2312-->unicode out=?″.
?.欢浠?TF-8杩.?缂..姝ゆ.?.ut涓轰贡?.?璇风.涓..?..杩..杈..?版.锛
FFFFFFE5 FFFFFF8D FFFFFFA1 FFFFFFE5 FFFFFF8F FFFFFF8B
Again !
unicode-->gb2312 out=卡友
====》结论,C程序自身产生的字符编码(即内码)与源文件以何种方式进行编程有关。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
以下是摘抄网上iconv的实现部分:
http://blog.csdn.net/yukin_xue/article/details/7652154
-----------------------------------------------------------------------------------------------------------------
在LINUX上进行编码转换时,既可以利用iconv函数族编程实现,也可以利用iconv命令来实现,只不过后者是针对文件的,即将指定文件从一种编码转换为另一种编码。
一、利用iconv函数族进行编码转换
iconv函数族的头文件是iconv.h,使用前需包含之。
#include <iconv.h>
iconv函数族有三个函数,原型如下:
(1) iconv_t iconv_open(const char *tocode, const char *fromcode);
此函数说明将要进行哪两种编码的转换,tocode是目标编码,fromcode是原编码,该函数返回一个转换句柄,供以下两个函数使用。
(2) size_t iconv(iconv_t cd,char **inbuf,size_t *inbytesleft,char **outbuf,size_t *outbytesleft);
此函数从inbuf中读取字符,转换后输出到outbuf中,inbytesleft用以记录还未转换的字符数,outbytesleft用以记录输出缓冲的剩余空间。 (3) int iconv_close(iconv_t cd);
此函数用于关闭转换句柄,释放资源。
相关实例:
例子1: 用C语言实现的转换示例程序
}