一、C++11對Unicode的支持
在C++98中,引入wchar_t對Unicode支持,但是后來由于不同平臺下wchar_t的寬度并不相同(8,16,32位),導致可移植性受到影響。因此從C++11開始引入了char16_t、char32_t以及原有的char,分別存儲utf16,utf32和utf8編碼的數據。
此外還定義了字符串常量的前綴:
- u8表示以utf8編碼
- u表示utf16編碼
- U表示utf32編碼
以上三種,再加上wchar_t格式的L以及不帶前綴的字符串,C++11則包含了5種字符串常量的前綴。
通常情況下,對于連續的字符串常量,C++會要求編譯器將其連起來,比如"a" "b"和"ab"沒有區別。
此外,對于多個連續聲明的字符串常量,只要有一個有前綴,則編譯器會將這些連續的字符串常量都以此前綴處理。(實際上vs2017并不允許)
此外,C++11還支持"\u十六進制碼位"表示unicode字符。
std::string str = "\u4F60\u597d"; //中文字符:你好
而想要正確顯示一個字符(不亂碼),要求輸入編碼格式、文件存儲編碼格式,編譯時選擇的編碼格式、以及輸出顯示編碼格式四者一致才能正確,否則都會出現亂碼的現象。
二、對于Unicode庫的支持
1.單碼位轉換
size_t mbrtoc16(char16_t * pc16, const char * s, size_t n, mbstate_t * ps);size_t c16rtomb(char * s, char16_t c16, mbstate _t * ps);size_t mbrtoc32(char32_t * pc32, const char * s, size_t n, mbstate_t * ps);size_t c32rtomb(char * s, char32_t c32, mbstate_t * ps);
mb表示multiple bytes,這四個函數都表示單碼位的轉換。
#include <climits>
#include <clocale>
#include <cuchar>
#include <iomanip>
#include <iostream>
#include <string>int main()
{std::setlocale(LC_ALL, "en_US.utf8");std::u16string strv = u"z?水🍌"; // or z\u00df\u6c34\U0001F34Cstd::cout << "Processing " << strv.size() << " UTF-16 code units: [ ";for (char16_t c : strv)std::cout << std::showbase << std::hex << static_cast<int>(c) << ' ';std::cout << "]\n";std::mbstate_t state{};char out[MB_LEN_MAX]{};for (char16_t c : strv){std::size_t rc = std::c16rtomb(out, c, &state);std::cout << static_cast<int>(c) << " converted to [ ";if (rc != (std::size_t) - 1)for (unsigned char c8 : std::string{ out, rc })std::cout << +c8 << ' ';std::cout << "]\n";}
}
#include <clocale>
#include <cstring>
#include <cuchar>
#include <cwchar>
#include <iomanip>
#include <iostream>int main()
{std::setlocale(LC_ALL, "en_US.utf8");std::string str = "z\u00df\u6c34\U0001F34C"; // or u8"z?水🍌"std::cout << "Processing " << str.size() << " bytes: [ " << std::showbase;for (unsigned char c : str)std::cout << std::hex << +c << ' ';std::cout << "]\n";std::mbstate_t state{}; // zero-initialized to initial statechar16_t c16;const char *ptr = &str[0], *end = &str[0] + str.size();while (std::size_t rc = std::mbrtoc16(&c16, ptr, end - ptr + 1, &state)){std::cout << "Next UTF-16 char: " << std::hex<< static_cast<int>(c16) << " obtained from ";if (rc == (std::size_t) - 3)std::cout << "earlier surrogate pair\n";else if (rc == (std::size_t) - 2)break;else if (rc == (std::size_t) - 1)break;else{std::cout << std::dec << rc << " bytes [ ";for (std::size_t n = 0; n < rc; ++n)std::cout << std::hex << +static_cast<unsigned char>(ptr[n]) << ' ';std::cout << "]\n";ptr += rc;}}
}
2.多碼位轉換
std::codecvt<char, char, std::mbstate_t> // 完成多字節與char之間的轉換std::codecvt<char16_t, char, std::mbstate_t> // 完成UTF-16與UTF-8間的轉換std::codecvt<char32_t, char, std::mbstate_t> // 完成UTF-32與UTF-8間的轉換std::codecvt<wchar_t, char, std::mbstate_t> // 完成多字節與wchar_t之間的轉換
以及派生codecvt_utf8、codecvt_utf16、codecvt_utf8_utf16等可以用于字符串轉換的模板類。這些模板類配合C++11定義的wstring_convert模板,可以進行一些不同字符串的轉換。
三、原生字符串字面量支持
C++11開始支持原生字符串字面量,語法是R"(string)".
#include <iostream>int main()
{std::cout << "12345\t\n890" << std::endl;std::cout << R"(12345\t\n890)" << std::endl;
}
輸出:
12345
890
12345\t\n890
而原生字符串字面值也可以添加前綴u,u8,U等表示字符編碼內容:
std::cout << uR"(12345\t\n890)" << std::endl;std::cout << UR"(12345\t\n890)" << std::endl;std::cout << u8R"(12345\t\n890)" << std::endl;
輸出:
006DEBE4
006DEB3C
12345\t\n890