DrY*_*Yap 43 c++ string unicode unicode-string c++11
我一直在寻找一种在Unicode字符串类型之间进行转换的方法,并且遇到了这种方法.我不仅没有完全理解方法(没有评论),而且文章暗示将来会有更好的方法.
如果这是最好的方法,请指出是什么让它起作用,如果不是,我想听听有关更好方法的建议.
bam*_*s53 87
mbstowcs()并且wcstombs()不一定转换为UTF-16或UTF-32,它们转换为wchar_t和语言环境wchar_t编码无关.所有Windows语言环境都使用两个字节wchar_t和UTF-16作为编码,但其他主要平台使用wchar_t带有UTF-32 的4字节(对于某些语言环境甚至使用非Unicode编码).只支持单字节编码的平台甚至可以有一个字节,wchar_t并且编码因语言环境而异.因此wchar_t在我看来,对于可移植性和Unicode来说,这是一个糟糕的选择.*
在C++ 11中引入了一些更好的选项; std :: codecvt的新特化,新的codecvt类,以及一个新的模板,使用它们进行转换非常方便.
首先,使用codecvt的新模板类是std :: wstring_convert.一旦创建了std :: wstring_convert类的实例,就可以轻松地在字符串之间进行转换:
std::wstring_convert<...> convert; // ... filled in with a codecvt to do UTF-8 <-> UTF-16
std::string utf8_string = u8"This string has UTF-8 content";
std::u16string utf16_string = convert.from_bytes(utf8_string);
std::string another_utf8_string = convert.to_bytes(utf16_string);
Run Code Online (Sandbox Code Playgroud)
为了进行不同的转换,您只需要不同的模板参数,其中一个是codecvt方面.以下是一些易于使用wstring_convert的新方面:
std::codecvt_utf8_utf16<char16_t> // converts between UTF-8 <-> UTF-16
std::codecvt_utf8<char32_t> // converts between UTF-8 <-> UTF-32
std::codecvt_utf8<char16_t> // converts between UTF-8 <-> UCS-2 (warning, not UTF-16! Don't bother using this one)
Run Code Online (Sandbox Code Playgroud)
使用这些的例子:
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
std::string a = convert.to_bytes(u"This string has UTF-16 content");
std::u16string b = convert.from_bytes(u8"blah blah blah");
Run Code Online (Sandbox Code Playgroud)
新的std :: codecvt特化有点难以使用,因为它们具有受保护的析构函数.要解决这个问题,您可以定义具有析构函数的子类,或者您可以使用std :: use_facet模板函数来获取现有的codecvt实例.此外,这些特化的问题是您无法在Visual Studio 2010中使用它们,因为模板特化不适用于typedef类型,并且编译器将char16_t和char32_t定义为typedef.这是定义自己的codecvt子类的示例:
template <class internT, class externT, class stateT>
struct codecvt : std::codecvt<internT,externT,stateT>
{ ~codecvt(){} };
std::wstring_convert<codecvt<char16_t,char,std::mbstate_t>,char16_t> convert16;
std::wstring_convert<codecvt<char32_t,char,std::mbstate_t>,char32_t> convert32;
Run Code Online (Sandbox Code Playgroud)
char16_t特化在UTF-16和UTF-8之间转换.char32_t专业化,UTF-32和UTF-8.
请注意,C++ 11提供的这些新转换不包括在UTF-32和UTF-16之间直接转换的任何方式.相反,你只需要组合两个std :: wstring_convert实例.
*****我想我会在wchar_t及其目的上添加一个注释,以强调为什么它通常不应该用于Unicode或便携式国际化代码.以下是我的答案的简短版本/sf/answers/777536721/
wchar_t的定义使得任何语言环境的char编码都可以转换为wchar_t,其中每个wchar_t只代表一个代码点:
类型wchar_t是一种不同的类型,其值可以表示支持的语言环境(22.3.1)中指定的最大扩展字符集的所有成员的不同代码.- [basic.fundamental] 3.9.1/5
这并不要求wchar_t足够大以同时表示来自所有语言环境的任何字符.也就是说,用于wchar_t的编码可能在区域设置之间不同.这意味着您不一定使用一个语言环境将字符串转换为wchar_t,然后使用另一个语言环境转换回char.
由于这似乎是wchar_t在实践中的主要用途,你可能想知道如果不是那样有什么好处.
wchar_t的最初目的和目的是通过定义文本处理使其简单,使得它需要从字符串的代码单元到文本字符的一对一映射,从而允许使用与ascii字符串一起使用的相同简单算法与其他语言合作.
不幸的是,对wchar_t的要求假定字符和代码点之间的一对一映射来实现这一点.Unicode打破了这种假设,因此您无法安全地将wchar_t用于简单的文本算法.
这意味着便携式软件不能将wchar_t用作语言环境之间文本的通用表示,也不能使用简单的文本算法.
对于便携式代码而言,并不多.如果__STDC_ISO_10646__已定义,则wchar_t的值直接表示在所有语言环境中具有相同值的Unicode代码点.这样可以安全地进行前面提到的区域间转换.但是,您不能仅仅依靠它来决定是否可以这样使用wchar_t,因为虽然大多数unix平台都定义了它,但即使Windows在所有语言环境中使用相同的wchar_t语言环境,Windows也不会.
__STDC_ISO_10646__我认为Windows没有定义的原因是因为Windows使用UTF-16作为其wchar_t编码,并且因为UTF-16使用代理对来表示大于U + FFFF的代码点,这意味着UTF-16不满足要求对__STDC_ISO_10646__.
对于特定于平台的代码,wchar_t可能更有用.它在Windows上基本上是必需的(例如,某些文件根本无法在不使用wchar_t文件名的情况下打开),尽管Windows是唯一一个这样的平台,据我所知(因此我们可以将wchar_t视为'Windows_char_t').
事后看来,wchar_t显然对简化文本处理或作为区域设置独立文本的存储没有用.便携式代码不应尝试将其用于这些目的.
dim*_*4eg 12
我编写了帮助函数来转换为UTF8字符串(C++ 11):
#include <string>
#include <locale>
#include <codecvt>
using namespace std;
template <typename T>
string toUTF8(const basic_string<T, char_traits<T>, allocator<T>>& source)
{
string result;
wstring_convert<codecvt_utf8_utf16<T>, T> convertor;
result = convertor.to_bytes(source);
return result;
}
template <typename T>
void fromUTF8(const string& source, basic_string<T, char_traits<T>, allocator<T>>& result)
{
wstring_convert<codecvt_utf8_utf16<T>, T> convertor;
result = convertor.from_bytes(source);
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
// Unicode <-> UTF8
{
wstring uStr = L"Unicode string";
string str = toUTF8(uStr);
wstring after;
fromUTF8(str, after);
assert(uStr == after);
}
// UTF16 <-> UTF8
{
u16string uStr;
uStr.push_back('A');
string str = toUTF8(uStr);
u16string after;
fromUTF8(str, after);
assert(uStr == after);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
35371 次 |
| 最近记录: |