字符编码基础ASCII
ASCII 是一种 7 位编码,用 0 到 127 之间的数值来代表最常用的字符
对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表一个字符(ASCII编码),而这之外的字符通常是使用0x80~0xFF范围内的两个字节来表示一个字符。比如汉字找那个的'汉'在简体中文中使用[0xBA, 0xBA]这两个字节存储。
为了使计算机支持多种语言,不同的国家和地区制定了不同的标准,由此产生了 GB2312, Big5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,繁体中文使用Big5,在日文操作系统下,ANSI 编码代表 JIS 编码。同时字节表示 ASCII 字符而用双字节表示 GB2312 中的字符;由于 GB2312 中本身也含有 ASCII 中包含的字符,在使用中逐渐就形成了“半角”和“全角”的区别。
中文操作系统中的‘汉’ |
||
char |
ANSI(GBK) |
UTF-8 |
Unicode(0x6C49) |
BABA |
0xE6B189 |
内存占用小
1.需要完整遍历整个字符串才能确定每个字符的位置
2.查找性能差,同时无法国际化使用,主流的代替方式是UTF-8
3.Unicode某些特殊值无法表示??,打开某些特殊字符文件夹失败,如包含表情的文件夹,甚至有可能用户名带emoji符号。
string test_name = "汉汉";
string test_name1 = "\u6C49\U0001F600\u6C49";
string test_name2 = "汉汉";
Unicode 在今天已经大大超出了最初的目标。到 Unicode 12.1 为止,Unicode 已经包含了 137,994 个字符,囊括所有主要语言(使用中的和已经不再使用的),并包含了表情符号、数学符号等各种特殊字符。Unicode 的编码点是从 0x0 到 0x10FFFF,一共 1,114,112 个位置。一般用“U+”后面跟 16 进制的数值来表示一个 Unicode 字符,如 U+0020 表示空格,U+6C49 表示“汉”,U+1F600 表示“”,等等(不足四位的一般写四位)。
32 比特,是编码点的直接映射。
对于从 U+0000 到 U+FFFF 的字符,使用 16 比特的直接映射;对于大于 U+FFFF 的字符,使用 32 比特的特殊映射关系——在 Unicode 的 16 比特编码点中 0xD800–0xDFFF 是一段空隙,使得这种变长编码成为可能。在一个 UTF-16 的序列中,如果看到内容是 0xD800–0xDBFF,那这就是 32 比特编码的前 16 比特;如果看到内容是 0xDC00–0xDFFF,那这是 32 比特编码的后 16 比特;如果内容在 0xD800–0xDFFF 之外,那就是一个 16 比特的映射。
wstring test_name = L"\u6C49\U0001F600\u6C49";
wstring test_name1 = L"汉汉";
1 到 4 字节的变长编码。在一个合法的 UTF-8 的序列中,如果看到一个字节的最高位是 0,那就是一个单字节的 Unicode 字符;如果一个字节的最高两比特是 10,那这是一个 Unicode 字符在编码后的后续字节;否则,这就是一个 Unicode 字符在编码后的首字节,且最高位开始连续 1 的个数表示了这个字符按 UTF-8 的方式编码有几个字节。
Unicode编码 |
UTF-8编码(二进制) |
U+0000 – U+007F |
0xxxxxxx |
U+0080 – U+07FF |
110xxxxx 10xxxxxx |
U+0800 – U+FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
U+10000 – U+10FFFF |
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
char u8str[] = u8"汉汉";
Windows 由于历史原因和保留向后兼容性的需要,一直用 char 表示传统编码(如,英文 Windows 上是 Windows-1252,简体中文 Windows 上是 GBK),用 wchar_t 表示 UTF-16。由于传统编码一次只有一种、且需要重启才能生效,要得到好的多语言支持,在和操作系统交互时必须使用 UTF-16。
由于窄字符在大部分 Windows 系统上只支持传统编码,要打开一个当前编码不支持的文件名称,就必须使用宽字符的文件名。微软的 fstream 系列类及其 open 成员函数都支持 const wchar_t* 类型的文件名,这是 C++ 标准里所没有的。
现代 Unix 系统,包括 Linux 和 Mac OS 在内,已经全面转向了 UTF-8。这样的系统中一般直接使用 char[] 和 string 来代表 UTF-8 字符串,包括输入、输出和文件名
支持 Unicode 及其转换的 API。
ansi string to wstring
UTF-8 string to wstring
wstring to ansi stirng
wstring to uft-8stirng
std::wstring trans(const std::string& sInput, int type) {
if (sInput.empty())
{
return L"";
}
int length = ::MultiByteToWideChar(type, 0, sInput.c_str(), -1, 0, 0);
wchar_t* result = new wchar_t[length + 1];
::memset(result, 0, (length + 1) * 2);
::MultiByteToWideChar(type, 0, sInput.c_str(), -1, result, length);
std::wstring strResult = result;
delete[] result;
result = nullptr;
return strResult;
}
// 当type为CP_ACP时,UNICODE转化为GBK;当type为CP_UTF8时,UNICODE转化为UTF8
std::string trans(const std::wstring& wsInput, int type) {
if (wsInput.empty())
{
return "";
}
int length = ::WideCharToMultiByte(type, 0, wsInput.c_str(), -1, 0, 0, 0, 0);
char* result = new char[length + 1];
::memset(result, 0, length + 1);
::WideCharToMultiByte(type, 0, wsInput.c_str(), -1, result, length, 0, 0);
std::string strResult = result;
delete[] result;
result = nullptr;
return strResult;
}