你的问题包含多个方面,我会尝试回答其中最重要的几个。
问:我有一个C++字符串,例如"Eat, drink, 愛"
,它是UTF-8、UTF-16还是UTF-32字符串?
答:这是由具体实现定义的。在许多实现中,这将是一个UTF-8字符串,但这并不是标准所规定的。请参考文档。
问:我有一个宽的C++字符串,例如L"Eat, drink, 愛"
,它是UTF-8、UTF-16还是UTF-32字符串?
答:这是由具体实现定义的。在许多实现中,这将是一个UTF-32字符串。在其他一些实现中,它将是一个UTF-16字符串。这些都不是标准规定的。请参考文档。
问:如何编写可移植的UTF-8、UTF-16或UTF-32 C++字符串字面量?
答:在C++11中有一种方法:
u8"I'm a UTF-8 string."
u"I'm a UTF-16 string."
U"I'm a UTF-32 string."
在C++03中,没有这样的运气。
问:字符串"Eat, drink, 愛"
至少包含一个UTF-32字符吗?
答:没有所谓的UTF-32字符(以及UTF-16和UTF-8)。它们都是UTF-32等字符串。它们都包含Unicode字符。
问:什么是Unicode字符?
答:它是由Unicode标准定义的编码字符集中的一个元素。在C++程序中,它可以用不同的方式表示,最简单和直接的方法是用一个与字符代码点对应的单个32位整数值。(为简单起见,在此忽略复合字符,并将“字符”和“代码点”视为相等,除非另有说明)。
问:给定一个Unicode字符,如何转义它?
答:检查它的值。如果它在256到65535之间,则打印一个2字节(4个十六进制数字)转义序列。如果大于65535,则打印一个3字节(6个十六进制数字)转义序列。否则,按正常方式打印它。
问:给定一个UTF-32编码的字符串,如何分解为字符?
答:字符串的每个元素(称为代码单元)对应于一个单独的字符(代码点)。只需一个接一个地获取它们,不需要特殊处理。
问:给定一个UTF-16编码的字符串,如何分解为字符?
答:值(代码单元)位于0xD800到0xDFFF范围之外,对应于具有相同值的Unicode字符。对于每个这样的值,打印一个普通字符或一个2字节(4个十六进制数字)转义序列。在0xD800到0xDFFF范围内的值被分组成一对,每对表示U+10000到U+10FFFF范围中的一个单一字符(代码点)。对于这样的一对,打印一个3字节(6个十六进制数字)转义序列。要将一对(v1,v2)转换为其字符值,使用以下公式:
c = (v1 - 0xd800) >> 10 + (v2-0xdc00)
请注意,对于一个合法的pair来说,第一个元素必须在0xd800..0xdbff范围内,第二个元素必须在0xdc00..0xdfff范围内,否则该pair将是不合法的。
问:如何将一个UTF-8编码的字符串分解成字符?
答:UTF-8编码比UTF-16编码更为复杂,我这里不会详细说明。你可以在互联网上搜索到很多描述和示例实现。
问:我的L"प्रे"字符串怎么了?
答:它是一个由四个Unicode代码点组成的组合字符,分别是U+092A、U+094D、U+0930、U+0947。请注意,这与用代理对表示高代码点的情况不同,关于此,请参见答案中的UTF-16部分。这是“字符”与“代码点”不同的情况。请分别转义每个代码点。在这个抽象层次上,你正在处理代码点,而不是实际的字符。当你将它们显示给用户或者计算它们在打印文本中的位置时,字符才会发挥作用,但处理字符串编码时不会。
Eat, drink, 愛
?你的问题似乎是将其存储为未指定编码的字节数组,并尝试猜测每个单独字符的编码,而不是整个数组的编码。 - user743382