GB UTF-8 UNICODE 汉字编码表:http://blog.chinaunix.net/uid-25544300-id-3281847.html

1.在使用libjson的过程中遇到的编码问题

push_back(JSONNode("中文","中文"))存进去的汉字,write()出来全变成了"\u00E6\u009A\u0097\u00E6\u0088\u0098"这种形式。

研究发现 E6 9A 97正是“暗”的UTF-8汉字编码。

“暗”的UNICODE编码是“6697”。std::cout<<"\u6697"<<std::endl和printf("\u6697\n")都会输出“暗”。

那么如何使E6 9A 97输出对应汉字呢?

char ch[] = {0xE6, 0x9A, 0x97, 0x00};

std::cout<<ch<<std::endl和printf("%s\n",ch)输出“暗”

2.

iconv各种转码,宽字符、多字符转换,都解决不了问题,最后用strlen一测,结果是一个“\u00E6”是六个字节,说明做了转义处理。需要自己转码。

3.宽字符、多字符转换

3.1 宽字符转多字符函数:int wcstombs(char *dest, wchar_t *src, int max)

把src宽字符串转换成普通字符串存储到dest,max表示允许转换到dest的最大字符数。

返回值:成功返回成功转换的普通字符数、转换到dest的普通字符数。失败返回-1,错误码在errno中。

确定dest大小

int n = wcstombs(NULL, src, 0);
char dest[n+1];
memset(dest, 0, n+1);

3.2 多字符转宽字符函数:int mbstowcs(wchar_t *dest, char *src, int max)

把src普通字符串转换成宽字符串存储到dest,max表示允许转换到dest的最大宽字符数。

返回值:成功返回成功转换的宽字符数、转换到dest的宽字符数。失败返回-1,错误码在errno中。

确定dest大小

int n = mbstowcs(NULL, src, 0);
wchar_t dest[n+1];
memset(dest, 0, n+1);

3.3 汉字转换

要加setlocale(LC_ALL,"zh_CN.UTF-8")或者setlocale(LC_ALL,"") ,否则error : Invalid or incomplete multibyte or wide character。

3.4 宽字符转普通字符函数模板

int wcstombs2(wchar_t *wch, std::string& str){
setlocale(LC_ALL, "");
int n = wcstombs(NULL, wch, 0);
if(n == -1){
std::cout<<"wcstombs:NULL error : "<<strerror(errno)<<std::endl;
return -1;
}
char ch[n+1];
memset(ch, 0, n+1);
int res = wcstombs(ch, wch, n);
if(res == -1){
std::cout<<"wcstombs:ch error : "<<strerror(errno)<<std::endl;
return -1;
}
str = ch;
return 0;
}

用法:

                wchar_t wch[] = {0x8363, 0x738b, 0x516b, 0x0};
std::string str;
if(wcstombs2(wch, str) == -1){
std::cout<<"transform fail"<<std::endl;
return -1;
}
std::cout<<str<<std::endl;    //输出“荣王八”

3.5 标准格式、参考实例

        setlocale(LC_ALL,"zh_CN.UTF-8");
wchar_t wch[] = L"九州";
int n = wcstombs(NULL, wch, 0);
if(n ==-1){
std::cout<<"wcstombs error : "<<strerror(errno)<<std::endl;
return -1;
}
char ch[n+1];
memset(ch, 0, n+1);
int res = wcstombs(ch, wch, n);
if(res ==-1){
std::cout<<"wcstombs error : "<<strerror(errno)<<std::endl;
return -1;
}
printf("%d\n%s\n", res, ch);
        setlocale(LC_ALL, "zh_CN.UTF-8");
char ch[] = "泥马";
int n = mbstowcs(NULL, ch, 0);
if(n ==-1){
std::cout<<"mbstowcs error : "<<strerror(errno)<<std::endl;
return -1;
}
wchar_t wch[n+1];
wmemset(wch, 0, n+1);
int res = mbstowcs(wch, ch, n);
if(res ==-1){
std::cout<<"mbstowcs error : "<<strerror(errno)<<std::endl;
return -1;
}
printf("%d\n%S\n",res,wch);

对这两函数有任何不理解就看:http://blog.csdn.net/xiaobai1593/article/details/7063535

4.iconv转码

4.1 编码转换函数:int iconv(iconv_t cd, char **s, size_t *b, char **c, size_t *d)

按照函数iconv_t iconv_open(const char *tocode, const char *fromcode)中指定的编码转化方式,将源字符串转换到目的字符串中。b是原串长度,d是目的地址空间大小。

#include <iconv.h>
char src[] = {0x63, 0x83, 0x53, 0x66, 0x1B, 0x54, 0x00};
char dest[100] = {0};
char *src_temp = src;
char *dest_temp = dest;
size_t src_len = strlen(src);
size_t dest_len = 100;
iconv_t cd = iconv_open("UTF-8","UNICODE");
if(cd < 0){
std::cout<<"iconv open error : "<<strerror(errno)<<std::endl;
return -1;
}
int res = iconv(cd, &src_temp, &src_len, &dest_temp, &dest_len);
if(res == -1){
std::cout<<"iconv error : "<<strerror(errno)<<std::endl;
return -1;
}
std::cout<<"dest = "<<dest<<std::endl;
iconv_close(cd);

4.2 编码转换函数模板

int iconv2(std::string& str, const char *tocode, const char *fromcode){
int n = str.length();
char src[n+1];
char dest[4*n+1];    //任何两种编码之间转换,源串与转换后的目的串大小不会超过4倍
char *src_temp = src;
char *dest_temp = dest;
size_t src_len = n;
size_t dest_len = 4*n;
memset(src, 0, n+1);
memset(dest, 0, 4*n+1);
memcpy(src, str.c_str(),n);
iconv_t cd = iconv_open(tocode, fromcode);
if(cd < 0){
std::cout<<"iconv_open error : "<<strerror(errno)<<std::endl;
return -1;
}
int res = iconv(cd, &src_temp, &src_len, &dest_temp, &dest_len);
if(res == -1){
std::cout<<"iconv error : "<<strerror(errno)<<std::endl;
return -1;
}
str = dest;
iconv_close(cd);
return 0;
}

5."\\u8d8a\\u6765\\u8d8a\\u6d41\\u884c\\u3002"

5.1 根据UNICODE与普通字符的适应性(7.3)

8d8a 6765 8d8a 6d41 884c 3002 分别是 “越”      “来”      “越”      “流”      “行”      “。”      的UNICODE编码,限期将其正确解码:

int main(){
char ch[] = "\\u8d8a\\u6765\\u8d8a\\u6d41\\u884c\\u3002";
std::string str(ch);
if(u_decode(str) == -1){
std::cout<<"u_decode error"<<std::endl;
return -1;
}
std::cout<<str<<std::endl;    //输出:越来越流行。
return 0;
}

u_decode函数:

int u_decode(std::string& str){
/*create unicode characters corresponding to characters*/
int index = 0;
int i = 0;
std::string substr;
int n = count(str, "\\u");
char src[2*n+3];
memset(src, 0, 2*n+3);
src[i++] = 0xfe;
src[i++] = 0xff;
while((index = str.find("\\u", index)) != std::string::npos){
index += 2;
substr = str.substr(index, 2);
src[i++] = strtol(substr.c_str(), NULL, 16);
index += 2;
substr = str.substr(index, 2);
src[i++] = strtol(substr.c_str(), NULL, 16);
}
str = src;
/*code from unicode to utf-8*/
int res = iconv2(str, "UTF-8", "UNICODE");
if(res == -1){
std::cout<<"iconv2 error"<<std::endl;
return -1;
}
return 0;
}

5.2 根据UNICODE与宽字符的适应性(7.6)

int main(){
char ch[] = "\\u8d8a\\u6765\\u8d8a\\u6d41\\u884c\\u3002";
std::string str(ch);
int n = count(str, "\\u");
wchar_t wch[n+1];
wmemset(wch, 0, n+1);
int i = 0;
int index = 0;
std::string substr;
while((index = str.find("\\u", index)) != std::string::npos){
index += 2;
substr = str.substr(index, 4);
wch[i++] = strtol(substr.c_str(), NULL, 16);
}
setlocale(LC_ALL, "");
printf("%S\n", wch);   //输出宽字符:“越来越流行。”
std::string outbuf;
if(wcstombs2(outbuf, wch) == -1){
std::cout<<"transform fail"<<std::endl;
return -1;
}
std::cout<<outbuf<<std::endl;    //输出普通字符:“越来越流行。”
return 0;
}

6.UTF-8汉字编码

UTF-8用三个字节表示一个汉字,如 0xE6 0x8B 0x97

6.1

char ch[] = {0xe5, 0xbe, 0x95, 0x00};   //此时ch中存储的就是汉字“徕”
std::cout<<ch<<std::endl;    //输出“徕”

6.2 \uXXXX对应的汉字以UTF-8编码存储(XXXX对应汉字的UNICODE编码)

printf("%s\n","\u5f95");   //输出“徕”
char ch[] = "\u5f95";
for(int i = 0; i < strlen(ch); i++)
printf("%#x\n", ch[i]);

输出:

0xffffffe5

0xffffffbe

0xffffff95    //E5 BE 95对应“徕”的UTF-8编码

7.UNICODE汉字编码

UNICODE所有字符都用两字节表示,当然一个汉字对应两字节,如5F95

机器默认UTF-8,不能得知UNICODE真正的存储格式。

7.1 以UTF-8存储的汉字,用iconv函数转化成UNICODE编码:

char ch[] = "荣";    //ch[0] = 0xe8,ch[1] = 0x8d, ch[2] = 0xa3, ch[3] = 0x0
char dest[100] = {0};
iconv();
for(int i = 0; i < strlen(dest); i++)
printf("%#x\n", dest[i]);

输出:

0xffffffff
0xfffffffe
0x63
0xffffff83    //8363 是 “荣”的UNICODE编码

7.2 FF FE和FE FF是UTF-16的BOM前缀,用来标示大小端存储:

0x8363 是 “荣”的UNICODE编码

FF FE : 小端存储  ch[0] = 0x63  ch[1] = 0x83

FE FF : 大端存储  ch[0] = 0x83  ch[2] = 0x63

7.3 UNICODE与普通字符的适应性

char ch1[] = {0x63, 0x83, 0x00};

char ch2[] = {0xff, 0xfe, 0x63, 0x83, 0x00};

char ch3[] = {0xfe, 0xff, 0x83, 0x63, 0x00};

经过从iconv从UNICODE到UTF-8转码后,均可输出汉字“荣”。

7.4 以UTF-8存储的汉字,用iconv函数转化成UTF-16编码,得到的结果与7.1相同。

7.3中的字符串用iconv从UTF-16转到UTF-8,结果均可输出汉字“荣”。

结论:UNICODE和UTF-16均固定使用两个字节表示字符。平常所说的UNICODE编码就是UTF-16的。

7.5 荣 0x8363        王 0x738B        八 0x516B

char ch1[] = {0x63, 0x83, 0x8B, 0x73, 0x6B, 0x51, 0x00};

用iconv从UNICODE或UTF-16转码到UTF-8,均可输出“荣王八”。

7.6 UNICODE与宽字符的适应性:

荣 0x8363        王 0x738B        八 0x516B

wchar_t wc = 0x8363;

setlocale(LC_ALL, "");

printf("%C\n", wc);    //输出“荣”

wchar_t wch[] = {0x8363, 0x738b, 0x516b, 0x0};

setlocale(LC_ALL, "");

printf("%S\n", wch);   //输出“荣王八”

用wcstombs将wch从宽字符转到普通字符后,可以正常输出。“荣王八”以UTF-8存储在char[]中:

                wchar_t wch[] = {0x8363, 0x738b, 0x516b, 0x0};
std::string str;
if(wcstombs2(wch, str) == -1){
std::cout<<"transform fail"<<std::endl;
return -1;
}
std::cout<<str<<std::endl;    //输出“荣王八”
const char *ch = str.c_str();
for(int i = 0; i < strlen(ch); i++)
printf("%#x\n", ch[i]);
return 0;

输出:

荣王八
0xffffffe8
0xffffff8d
0xffffffa3    //“荣” utf-8编码:e8 8d a3
0xffffffe7
0xffffff8e
0xffffff8b    //"王" utf-8编码:e7 8e 8d
0xffffffe5
0xffffff85
0xffffffab    //"八" utf-8编码:e5 85 ab

8.有符号数

8.1 二进制数大小

最高位表示正负:

正数最高位为0,绝对值等于去掉符号位后二进制转十进制。

负数最高位为1,绝对值等于去掉符号位后的补码。(计算机是用补码来保存负数的)

计算机中求一个补码表示的负数值:去掉符号位后按位取反最后结果加1就是它的绝对值,或者简单点直接拿掉符号位后从最高位按位取反直到最后一个1,然后二进制转十进制,得到的也是绝对值。

求一个负数的补码:最高位1,然后用次高位到最低位表示出它的绝对值,按位取反加1,或者从次高位按位取反直到最后一个1。

8.2 有符号数扩充即扩展符号位。

8.3 char是有符号数,占八位,最高位表正负。

WINDOWS部分

4.mysql数据库乱码

前言:

VS2010默认汉字编码GB2312、mysql被设置成UTF8,故通过程序插入数据库中的“崇祯”为乱码。

过程描述:

1.原因一直没有找到,不停更改mysql数据库编码、table编码。

2.程序设置断点,debug下汉字正常显示。故认为乱码出在mysql。

3.后经刘XX提醒,即将插入mysql、正常显示的汉字以十六进制打出,对应编码表

结果:程序中正常显示的汉字编码为GB,结合mysql的UTF8,乱码不足为奇。

解决:

A.存mysql前不管汉字与否一律:首先默认编码转宽字符、最后宽字符转UTF8。

B.取mysql后不管汉字与否一律:首先UTF8转宽字符、最后宽字符转默认编码。

3.GBKGB2312的关系

1.

用GET从HTTP上请求了数据,用recv函数直接收到了char *buffer中,在VS中查看结果

HTTP/1.1 200 OK Date: Thu, 09 Jan 2014 01:29:15 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private Expires: Thu, 09 Jan 2014 01:29:15 GMT Content-Type: text/html; charset=utf-8 Content-Length: 387

[ { "GUID": "", "OID": -1, "ID": 4002, "UserID": null, "Name": "鏉庢瘏", "Sex": null, "NationCode": null, "Birthday": null, "IdentityCardID": null, "AreaCode": null, "HomeAddress": null, "WorkAddress": null, "TelephoneNum": null, "MobilePhoneNum": null, "NameSpell": null, "BabyName": "鏉庢檽鑹? } ]

问题来了,中文乱码了。。。

HTTP头信息中的charset=utf-8清楚的告诉下面我发到char *buffer中的字节流是utf8编码的。

解决方法:

int m = MultiByteToWideChar(CP_UTF8,0,buffer,-1,0,0);
WCHAR *temp = new WCHAR[m+1];
temp[m]='\0';
MultiByteToWideChar(CP_UTF8,0,buffer,-1,temp,m); 

然后:

m=WideCharToMultiByte(CP_ACP,0,temp,-1,0,0,0,0);
char *result = new char[m+1];
result[m]='\0';
WideCharToMultiByte(CP_ACP,0,temp,-1,result,m,0,0);

我的理解是:

HTTP编码中给出了编码格式是UTF8,出现乱码的原因是系统使用的默认编码方式对011010的比特流解码,编码与解码不一致,必然出现乱码。所以第一步首先将buffer按照UTF8解码成UNICODE(windows下默认的貌似),参数CP_UTF8。然后再次将UNICODE转换成系统默认的编码,参数CP_ACP 指示 API 使用当前设置默认的 Windows ANSI 代码页进行转换。

收集的信息如下:

一个孤立的字符串的解释依赖于具体的系统,你如果在linux上开发,utf8的默认显示的是正确的,而如果你转成wchar_t反而会乱码。html/xml通过charset属性指明了对这些字节流的理解方式,所以不同平台上都可以正确显示。在各个系统的底层,可能都要转换成特定的编码方式再显示,比如utf-8的串在Windows上会转成unicode, unicode/gbk等编码方式的在linux下多半会转换成utf8串再显示。

Putf8不是操作系统默认的理解方式,所以出现乱码。

同样的二进制数据在不同的字符集中对应不同的字符,要把二进制数据作为文本显示必须指定字符集
高版本的VS在调试中显示数据时,对于wchar_t*指针指向的内存,按照UNICODE编码来对应字符集,对于char*指针指向的内存,按照ASCII编码和操作系统语言设置来对应字符集。当然这些都是显示方面的功能,对于程序本身执行的功能一点影响都没有。

如果你告诉它这个是utf8串,那它会理解,但你不告诉它它不会把所有可能的字符编码方式逐一试遍。

2.windowslinux收发汉字乱码

4月15号,VS2010,socket通信。

windows发汉字,linux收的是乱码;linux发汉字,windows收的是乱码。

windows使得是ANSI编码,说到ANSI编码这里我少说两句。ANSI表示英文字符时用一个字节、表示中文用两个字节,在简体中文系统下ANSI代表GB2312编码。而UNICODE万国码不管英文字符还是中文都用两字节表示。

linux下默认UTF8编码。编码不统一自然乱码。

解决方法:

发送前转UTF8:

inline std::string win2unix_decode(const char* buffer)
{
int m = MultiByteToWideChar(CP_ACP,0,buffer,-1,0,0);
WCHAR *temp = new WCHAR[m+1];
temp[m]='\0';
MultiByteToWideChar(CP_ACP,0,buffer,-1,temp,m);
m=WideCharToMultiByte(CP_UTF8,0,temp,-1,0,0,0,0);
char *result = new char[m+1];
result[m]='\0';
WideCharToMultiByte(CP_UTF8,0,temp,-1,result,m,0,0);
std::string str = result;
delete[] temp;
delete[] result;
return str;
}

接收后转ANSI:

inline std::string unix2win_decode(const char* buffer)
{
int m = MultiByteToWideChar(CP_UTF8,0,buffer,-1,0,0);
WCHAR *temp = new WCHAR[m+1];
temp[m]='\0';
MultiByteToWideChar(CP_UTF8,0,buffer,-1,temp,m);
m=WideCharToMultiByte(CP_ACP,0,temp,-1,0,0,0,0);
char *result = new char[m+1];
result[m]='\0';
WideCharToMultiByte(CP_ACP,0,temp,-1,result,m,0,0);
std::string str = result;
delete[] temp;
delete[] result;
return str;
}

CP_ACP即 ANSI。

字符编码 编码转换 乱码相关推荐

  1. 字符与编码(编码转换)

    作为一名程序员,肯定有被乱码困扰的时候,真到了百思不得其解的时候,就会觉得:英文程序员真幸福.但其实只要明白编码之间的转换规律,其实乱码还是很好解决的.我们都知道字符串在保存和传输的时候需要先经过编码 ...

  2. linux 保存文件名乱码怎么办,Linux 文件名编码转换 乱码 解决办法

    Linux中操作windows下的文件,可能会经常遇到文件编码转换的问题.Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8.下面介绍一下,在Linux中如何查看文 ...

  3. EBCDIC 与 GBK 的字符编码及其转换(转)

    概览 有些用户在使用 AIX 时在字符编码方面遇到一些困惑,请看下面的场景: 1,用户用从 AIX 利用 FTP 客户端登录上 IBM i,切换到某个 Library/File,然后 get 其中的某 ...

  4. 使用charCodeAt()和charAt()方法,根据Unicode 编码,转换字符

    1.charCodeAt() 方法 charCodeAt() 方法可返回指定位置的字符的 Unicode 编码.这个返回值是 0 - 65535 之间的整数. 方法 charCodeAt() 与 ch ...

  5. 计算机底层存储字节还是字符,彻底搞懂乱码——字符,字节和编码

    级别:中级 摘要:本文介绍了字符与编码的发展过程,相关概念的正确理解.举例说明了一些实际应用中,编码的实现方法.然后,本文讲述了通常对字符与编码的几种误解,由于这些误解而导致乱码产生的原因,以及消除乱 ...

  6. Java 字符的 编码 与 乱码 和恢复

    这里写目录标题 常见非Unicode编码 1.ASCII 2.ISO 8859-1 3.Windows-1252 4.GB2312 5.GBK 6.GB18030 7.Big5 8.编码汇总 2.3. ...

  7. 字符 字符集 编码 以及乱码

    字符: 各种文字和符号的总称,如一个符号,一个字母 字符集:表示所有字符的集合,就相当于一个二维表,收录能显示的所有的字符.常见的字符集合有ASCII,GB2312,GBK,GB18030,BIG5, ...

  8. 字符编码详解——彻底理解掌握编码知识,“乱码”不复存在

    每一个程序员都不可避免的遇到字符编码的问题,特别是做Web开发的程序员,"乱码问题"一直是让人头疼的问题,也许您已经很少遇到"乱码"问题,然而,对解决乱码的方法 ...

  9. javascript 西瓜一期 14 回顾 字符与编码 进制转换 数据保存

    回顾前情 >字符都有一个编码对应 比如 字符a对应的编码是97(十进制) 所以如果保存了一个内容,只是字符a 会把a对应的编码进行保存 然而97计算机也不可以直接识别 电脑会把十进制的97转换为 ...

最新文章

  1. 导出Windows服务器下的Oracle数据库并导入到Linux服务器下的Oracle数据库中
  2. 《为什么在多核处理器下需要内存屏障(MenmoryBarrier)?》
  3. 全球及中国养老产业十四五运营现状与发展决策建议报告2022版
  4. 百度外卖接口调试 C#版
  5. 防火墙未来的技术发展趋势
  6. Jupyter Notebook安装 nbextensions 插件
  7. 入门大爆炸式发展的深度学习,你先要了解这6个著名框架
  8. Docker Compose如何与SkyEye完美结合
  9. 操作系统饥饿现象_操作系统试题
  10. Android开发笔记(一百五十五)利用GL10描绘点、线、面
  11. 美国河流出现神奇冰盘 顺着水流不断旋转
  12. redis与mysql一致性方案解析
  13. 批量归一化Batch Normalization 动手学深度学习v2
  14. codeblock的汉化过程
  15. 康托尔点集matlab实数,仿照科赫曲线程序 , 按照课件上的算法写出康托尔点集 – MATLAB中文论坛...
  16. 郑捷《机器学习算法原理与编程实践》学习笔记(第三章 决策树的发展)(二)_C4.5...
  17. c语言自动贩卖机设计报告,自动贩卖机课程设计.doc
  18. php 下载的文件损坏,PHP readfile()导致文件下载损坏
  19. fish shell一个专为90后设计的命令行shell
  20. 机器视觉光源种类(环形光,条光,背光源,同轴光,线光,点光,穹顶光,开孔面光源等)

热门文章

  1. 危机下的车展,该看看百度Apollo车联网
  2. Staking研究报告 | TokenInsight
  3. 漏洞案例之z-blog后台文件上传
  4. java计算矩形的面积和周长的方法
  5. 拓嘉启远:怎样才能避免拼多多网店被限制
  6. 当机会来临的时候,你做好准备了吗
  7. KB5013942更新失败
  8. 测试晶面间距软件_材料现代测试分析方法期末考试卷加答案(精)
  9. java-php-python-ssm智慧后勤系统计算机毕业设计
  10. python控制硬件_用Python控制硬件14-脉冲驱动伺服电机