UTF-8 解码库

3
我需要在Windows的MSVC 10中编写Unicode UTF-8应用程序。我知道UTF-8编码的字符串会使用1个或2个字节来表示一个字符。那么我的问题是:std::string适合这种情况吗?如果是,我该如何解码字符串? 我理解std::string只是一个字节数组,它并不提供任何解码逻辑。如何确定字符串的逻辑长度? 如何从字符串中提取逻辑字符?是否有任何库可以帮助我从字符串中提取逻辑字符?
例如:如果我有一个包含"olé"的std::string,我需要知道它的长度为3而不是4。

6
UTF-8 可以使用每个字符最多 4 个字节,而不仅仅是一个或两个。 - deceze
1
你所说的解码字符串是什么意思?更重要的是,为什么需要知道长度?在Unicode中通常没有意义。 - Yakov Galka
3个回答

3

2

std::string 是可行的,但正如你所注意到的,它只能操作字节而非 Unicode 码点。在这方面,std::string 是一种不透明类型;这并不一定是坏事(实际上,它确实有一些优点,请参考下面的链接获取信息),但如果需要有关字符的信息,则需要对字符串进行解码。

对于实际处理 UTF-8(必要时),可以使用Boost.NoWide库来解码 UTF-8。

此外,我建议阅读UTF-8 到处都是宣言,了解有关使用 UTF-8 与其他 Unicode 转换的信息。


std::string让对字符串进行排序和测试字符变得非常困难。但是如果您不需要这样做,那么使用UTF-8字符串是完全可以使用std::string的。您还可以使用QString(Qt)或CString(MFC...)。 - Alexis Wilke
感谢@Konrad Rudolph提供的链接。它们很有用...从最初的一瞥来看,Boost.Nowide库似乎没有stringstream...但是,我需要仔细查看。 - PermanentGuest
1
@Alexis,为此您可以(实际上,必须)提供自定义比较器。这不仅限于std::string,即使在使用宽字符时也是如此,因为存在组合字符等情况。 - Konrad Rudolph
我认为你不能使用Boost.NoWide获取字符串中Unicode代码点的计数,除非它们全部都在BMP中。我发现Boost.NoWide对于I/O很有用,但它不提供Unicode字符串处理功能。 - smerlin
我从这篇文章中发现了一件有趣的事情:“Windows C++程序员被教育要使用‘widechars’来处理Unicode。由于这种混乱,他们现在是最困惑于如何正确处理文本的人之一。”我就是其中之一!! - PermanentGuest

-2

首先,您可能希望调用mbstowcs()函数将UTF-8字符转换为宽字符。然后,如果您希望结果为8位,则在存在“Unicode”字符(ISO-8859-1平面之外的字符,也称为Latin 1)的情况下将会有数据损失。

请注意,“Windows”编码与ISO-8859-1不是一对一等价的,但在大多数情况下,ISO-8859-1是人们现在使用的。

参考资料:http://www.cplusplus.com/reference/clibrary/cstdlib/mbstowcs/

好了,如果您只想得到字符长度,请使用mblen()函数:

len = mblen(str.c_str(), str.length());

附注:实现mblen()的简单方法是计算不在0x80和0xBF之间的字节数量,因为它们是多字节序列的一部分。如果您在不稳定的串行连接上接收到UTF-8字节序列,则此方法特别有用。

在大多数情况下,ISO-8859-1是人们现在使用的编码。在互联网上,我经常看到CP1252被错误地标记为ISO-8859-1。不确定在这种情况下你会说他们在“使用”哪一个,但最重要的是少数人的文本会破坏你的代码,而不是“大多数人”正在使用什么。;-) - Steve Jessop
或者考虑将其转换为UTF-16或UTF-32进行内部处理。 - ctrl-alt-delor
是的,UCS-2的前256个字符在转换后与UCS-4,UTF-16和UTF-8相同。它们都是ISO-8859-1。转换为另一种编码(例如CP1252)需要表格或像iconv这样的库(我建议您避免使用!)。 - Alexis Wilke
@Alexis Wilke: "一旦转换",正确。哦,顺便说一下,如果他们仍在使用8字节代码页,"人们现在使用的"通常是ISO-8859-15。随着欧元货币成为历史,这可能会改变,但目前Latin-1是"常见"的,因为人们无法记住它实际上是Latin-9... - DevSolar
嗯...欧元符号可以在ISO-8859-15、-16和-7中找到,而不是-9。无论如何,随着Unicode和互联网的发展,ISO-8859-1是你会听到的,因为所有其他8位编码都不能与Unicode中的任何其他平面一一对应。 - Alexis Wilke
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接