2010-10-16 38 views
10

我阅读了一些关于C++中字符串和字符编码最佳实践的文章,但是我正在努力寻找一种对我来说合理简单和正确的通用方法。我可以就以下问题征求意见吗?我倾向于使用UTF-8和UTF-32,并定义是这样的:C++中的字符串和字符编码

typedef std::string string8; 
typedef std::basic_string<uint32_t> string32; 

的string8类将被用于UTF-8,和具有单独的类型仅仅是一个编码的催。另一种方法是将string8作为std :: string的子类,并删除UTF-8不完全正确的方法。

当需要固定字符大小时,string32类将用于UTF-32。

UTF-8 CPP函数utf8 :: utf8to32()和utf8 :: utf32to8()甚至更简单的包装函数将用于在两者之间进行转换。

+0

请注意'string8'仍然与'std :: string'类型相同;它只是一个不同的名字。 – 2010-10-16 20:15:39

+0

哪个'std :: basic_string'函数*对于UTF-8是正确的? – dalle 2010-10-16 20:20:34

+0

UTF-32通过wstring/Unicode购买你什么?顺便说一句Visual Studio定义了'u16string'和'u32string'。 – 2010-10-16 20:31:04

回答

9

如果您计划只是传递字符串并且从不检查它们,您可以使用普通的std::string,尽管这是一个穷人的工作。

问题是,大多数框架,甚至标准,都愚蠢地(我认为)在内存中强制编码。我说愚蠢,因为编码只应该在接口上,并且这些编码不适用于数据的内存中操作。此外,编码很容易(这是一个简单的CodePoint转换 - >字节和相反),而主要难点实际上是操纵数据。

对于8位或16位,由于std::stringstd::wstring都不知道Unicode字符是什么,所以存在切割中间字符的风险。更糟糕的是,即使使用32位编码,也存在将字符从适用于其的变音符中分离出来的风险,这也是愚蠢的。

就标准而言,Unicode在C++中的支持因此是非常不利的。

如果你真的想操作Unicode字符串,你需要一个Unicode识别的容器。通常的方法是使用库,尽管它的接口真的是C-ish。但是,您将获得使用多种语言实际使用Unicode所需的一切。

+1

我发现你对有关diacritics的评论有点吓人。从某种意义上讲,它与我正在尝试做的事情最为相关,即以相对简单的方式“正确”处理字符串。 – nassar 2010-10-19 02:13:57

+0

@nassar:不幸的是它很可怕,因为我们缺乏适当的支持:'( – 2010-10-19 07:08:43

+0

)ICU(在C++的其他接口中)有一个与std :: string互操作的C++字符串类 – 2010-10-20 05:00:24

1

特征描述here可能会有所帮助。这是一种古老而有用的技术。

1

没有指定字符串编码必须用于字符串,wstring等常用的方法是在宽字符串中使用unicode。应使用哪些类型和编码取决于您的要求。

如果您只需要将数据从A传递给B,请选择使用UTF-8编码的std :: string(不要引入新类型,只需使用std :: string)。如果您必须使用字符串(提取,concat,sort,...)选择std :: wstring,并在Windows上对UCS2/UTF-16(仅限BMP)和Linux上的UCS4/UTF-32进行编码。 好处是固定大小:每个字符的大小为2(或UCS4为4)字节,而带有UTF-8的std :: string返回错误的length()结果。

对于转换,您可以检查sizeof(std :: wstring :: value_type)== 2或4以选择UCS2或UCS4。我正在使用ICU库,但可能有简单的包装库。

不建议派生自std :: string,因为basic_string不是为(缺少虚拟成员等)而设计的。如果你真的真的需要你自己的类型,如std :: basic_string < my_char_type>为此写一个自定义的专业化。

新的C++ 0x标准定义wstring_convert <>和wbuffer_convert <>与一个std ::的codecvt从窄字符集转换为宽字符集(例如UTF-8至UCS2)。 Visual Studio 2010已经实现了这个afaik。

+2

我特意避开了UCS-2,因为在我看来,如果有人要处理字符编码的麻烦,那么不妨做到这一点,并支持完整的Unicode。 (与此同时,我正在寻找一些比通用ICU更笨重的东西)。对于UTF-16,它似乎具有可变长度编码和使用大量内存的缺点。这就是为什么我建议结合使用UTF-8和UTF-32。 – nassar 2010-10-16 23:00:50

+0

关于从std :: string派生的点。谢谢! – nassar 2010-10-16 23:14:57

+1

我认为定义一个新类型并不重要,但很多在代码中看到std :: string的人往往会忘记多字节字符并错误地使用字符位置。它是UTF-8的事实可以在评论中传达,但在类型名称中提醒似乎很有帮助,因为在我看来,诸如std :: string :: insert()这样的方法确实提示了8位字符。 – nassar 2010-10-16 23:33:31