中文编码
gb2312 => gbk => gb18030
unicode在制定的时候没有考虑已有的编码, 所以和gb2312/gbk是不兼容的, 只能通过查表的方式进行转换.
详情参见: 笔记:ASCII, GB2312, GBK, Unicode, UTF8之间的区别和联系
unicode
unicode的出现是为了解决不同地区之间的编码混乱的问题.
unicode对世界上绝大部分的文字进行整理和统一编码. 编码空间为U+0000到U+10FFFF
.
unicode只是统一规定了哪个字符对应哪个编码, 并没有规定编码怎么存储. 实际实现的时候却可以有不同的方式, 常见的有: utf-8
/utf-16
/utf-32
/ucs2
/ucs4
.
utf-8
和utf-16
是变长的编码方案.
ucs2
和ucs4
是定长的编码方案.
utf-32
和ucs4
是等价的.
utf8
utf8(8-bit Unicode Transformation Format)是一种变长的编码方案, 以8bit(1byte)作为最小编码单位, 一个unicode码可以编码成1至4个字节.
编码规则如下表:
Unicode符号范围(十六进制) | UTF-8编码方式(二进制) |
0000 0000-0000 007F | 0xxxxxxx |
0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
utf16
utf16(16-bit Unicode Transformation Format)也是一种变长的编码方案, 以16bit(2byte)作为最小编码单元, 一个unicode码可以编码为1至2个码元, 每个码元占2个字节.
编码规则如下:
Unicode码在0x0000-0xffff
范围内的字符(也是绝大多数平时用到的字符)占一个码元, 并且码元的值和unicod码是相等的不需要额外转换.
对于超出0xffff
范围的Unicode码才需要进行编码.
utf32
utf32直接用4个字节存储一个unicode码, 不需要额外的编码规则.
ucs2(2-byte Universal Character Set)
是一种定长编码方式, 只能表示0x0000-0xffff
范围内的unicod码, 在这个范围内和utf16是等价的.
ucs4(4-byte Universal Character Set)
也是一种定长的编码方式, 用4个字节存一个字符, 所以可以存下所有的unicode码, 和utf32是等价的.
但是会存储空间.
BOM(Byte Order Mark)
码元超过1个字节的时候, 都会存在字节序的问题.
BOM(字节序标记)就是插入到UTF-8、UTF-16或UTF-32编码的Unicode文件开头的特殊标记, 用于标识文本编码及字节序.
编码 | BOM |
UTF-8 | 0xEF 0xBB 0xBF |
UTF-16 BE | 0xFE 0xFF |
UTF-16 LE | 0xFF 0xFE |
UTF-32 BE | 0x00 0x00 0xFE 0xFF |
UTF-32 LE | 0xFF 0xFE 0x00 0x00 |
c++对unicode的支持
参考: C++11新特性--Unicode支持
c++11引入了char16_t和char32_t类型来明确UTF-16和UTF-32编码方案对应的存储类型.
与之对应的STL库中多了相应的std::u16string和std::u32string.
char u8[] = u8"\u4f60\u597d\u554a";
char16_t u16[] = u"\u4f60\u597d\u554a";
char32_t u32[] = U"\u4f60\u597d\u554a";
//utf32 to utf16
std::u32string u32wstr(u32emoji);
std::wstring_convert<std::codecvt_utf16<char32_t , 0x10ffff, std::little_endian>, char32_t> utf16le_cvt;
std::string stru16bytes = utf16le_cvt.to_bytes(u32wstr);
char16_t* p16 = (char16_t*)(stru16bytes.c_str()); //观察内存可以看到大于2字节的emoji字符, 从u32转到u16, 做了相应的编码
//u16 to u8
//std::wstring_convert<std::codecvt_utf8<char16_t>, char16_t> utf8_ucs2_cvt;
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> utf8_ucs2_cvt;
std::string stru18emoji = utf8_ucs2_cvt.to_bytes(p16);
std::u16string stru16emoji = utf8_ucs2_cvt.from_bytes(stru18emoji);
//utf8 to u32
std::wstring_convert<std::codecvt_utf8<char32_t >, char32_t> u8_u32_convert;
std::string u32tou8 = u8_u32_convert.to_bytes(u32emoji); //u32 to u8
std::u32string stru32emoji = u8_u32_convert.from_bytes(stru18emoji);//u8 to u32
//uft8 to u16
std::wstring_convert<std::codecvt_utf8_utf16<char16_t >, char16_t> u8_u16_convert;
std::u16string stru16emoji2 = u8_u16_convert.from_bytes(stru18emoji);
linux下处理utf8编码
- 查看文件编码:
$ file [filename]
- 编码转换
$ iconv -f [from_encoding] -t [to_encoding] [inputfile] -o [outputfile]
$ iconv -f utf-8 -t unicode utf8file.txt > unicodefile.txt
// ...
iconv_t iconv_open(const char *tocode, const char *fromcode);
size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
int iconv_close(iconv_t cd);