编辑我意识到这是错误的开始后修改了问题。
我正在将一个C#应用程序的一部分移植到Linux,在那里我需要得到一个UTF-16string的字节:
string myString = "ABC"; byte[] bytes = Encoding.Unicode.GetBytes(myString);
所以bytes
数组现在是:
"65 00 66 00 67 00" (bytes)
我怎样才能在Linux上实现相同的C + +? 我有一个定义为std::string
的myString
,似乎Linux上的std::wstring
是4个字节?
最简单的方法是抓住一个小型图书馆,如UTF8 CPP ,做一些事情:
utf8::utf8to16(line.begin(), line.end(), back_inserter(utf16line));
你的问题不是很清楚,但我会尽力澄清一些困惑。
在C标准的'95修正案之后,C中字符集的处理状态(并且由C ++继承)。
所使用的字符集由当前语言环境给出
wchar_t
是为了存储代码点
char
是为了存储一个多字节编码的形式(一个约束,例如,基本字符集中的字符必须编码在一个字节)
字符串文字以实现定义的方式进行编码。 如果他们使用基本字符集之外的字符,则不能认为它们在所有语言环境中都是有效的。
因此,使用16位wchar_t
您只能使用BMP。 使用UTF-16的替代品是不合规的,但我认为MS和IBM或多或少被迫这样做,因为他们认为Unicode将永远是一个16位的字符集。 那些延迟Unicode支持的人倾向于使用32位wchar_t。
较新的标准不会有太大的改变。 UTF-8,UTF-16和UTF-32编码的字符串大部分都是字面值,并且有16位和32位字符的类型。 标准库中的Unicode很少或没有额外的支持。
你必须在使用Unicode的语言环境中。 希望
std::locale::global(locale(""));
就足够了。 如果没有,您的环境没有正确设置(或设置为另一个字符集,并假设Unicode将不会为您的用户提供服务)。
使用wcstomsb
和wcstomsb
函数。 这是你问的一个例子。
std::string narrow(std::wstring const& s) { std::vector<char> result(4*s.size() + 1); size_t used = wcstomsb(&result[0], s.data(), result.size()); assert(used < result.size()); return result.data(); }
语言环境的codecvt方面提供所需的功能。 好处是你不必改变使用它的全局语言环境。 不方便的是使用更复杂。
#include <locale> #include <iostream> #include <string> #include <vector> #include <assert.h> #include <iomanip> std::string narrow(std::wstring const& s, std::locale loc = std::locale()) { std::vector<char> result(4*s.size() + 1); wchar_t const* fromNext; char* toNext; mbstate_t state = {0}; std::codecvt_base::result convResult = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(loc) .out(state,&s[0], &s[s.size()], fromNext, &result[0], &result[result.size()], toNext); assert(fromNext == &s[s.size()]); assert(toNext != &result[result.size()]); assert(convResult == std::codecvt_base::ok); *toNext = '\0'; return &result[0]; } std::wstring widen(std::string const& s, std::locale loc = std::locale()) { std::vector<wchar_t> result(s.size() + 1); char const* fromNext; wchar_t* toNext; mbstate_t state = {0}; std::codecvt_base::result convResult = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(loc) .in(state, &s[0], &s[s.size()], fromNext, &result[0], &result[result.size()], toNext); assert(fromNext == &s[s.size()]); assert(toNext != &result[result.size()]); assert(convResult == std::codecvt_base::ok); *toNext = L'\0'; return &result[0]; }
你应该通过更好的处理来替换断言。
顺便说一句,这是标准的C ++,并不假定Unicode除了计算结果的大小,你可以通过检查可以指示部分转换convResult更好)。
我通常使用Poco C ++库中的UnicodeConverter类。 如果你不想要依赖,那么你可以看看代码。