我最近观看了Tom Scott from Computerphile talk about UTF-8,之后又进行了一些研究,了解UTF-8可用于编码最多6个字节的字符,每个字节使用以下标头:
0xxx xxxx # 1 Byte character
110x xxxx # 2 Byte character
1110 xxxx # 3 Byte character
1111 0xxx # 4 Byte character
1111 10xx # 5 Byte character
1111 110x # 6 Byte character
然后使用10xx xxxx
来表示额外的字节(我意识到RFC3629将此限制为仅最多4个字节)。
我理解这是否允许编码2,164,286个不同的字符(忽略任何保留字符)?
0xxx xxxx # 7 bits => 128
110x xxxx # 5 bits + 6 bits = 11 bits => 2,048
1110 xxxx # 4 bits + 6*2 bits = 16 bits => 65,536
1111 0xxx # 3 bits + 6*3 bits = 21 bits => 2,097,152
# == 2,164,864
理论上我可以使用char
数组来存储UTF-8编码的字符串,或者我可以使用固定长度编码(如UTF-32)并使用任何4字节类型,例如unsigned long
对每个UTF-8编码字符进行编码,但这会大大增加内存,只会使用仅使用1或2字节编码的UTF-8字符。
我相信std::string
允许存储UTF-8,这会导致size
和length
返回字节长度,但如果UTF-8可以表示不同长度的字符,那怎么做语言(我们将C ++用来限制这个问题的范围)在内部编码这些字符(例如在std::string
中)?
答案 0 :(得分:4)
UTF-8字符串是一些字节序列(即{C}中的char
- 或uint8_t
)遵循一些限制(因此并非每个字节序列都是有效的UTF-8 string;如果你从外面得到一些声称它是UTF-8的字符串,你应该验证它。)
因此,您可以使用std::string
- s来表示UTF-8字符串(前提是您确定它们是有效的UTF-8)。
您可以在其上方使用一些UTF-8库(例如libunistring或Glib Unicode Manipulation)。
换句话说,UTF-8可以被视为关于如何使用字符串(char
- s)的约定。
当然,请注意字节数(例如size()
的{{1}})不是 UTF-8字符的数量。并且您不能使用普通迭代器来迭代UTF-8字符(或它们的Unicode等价物)。
您可能会发现一些更多UTF-8感知的C ++库(例如Gtkmm中的Glibmm ustring - s)或代表Unicode字符串的库(例如Qt中的QString - s)。
BTW,UTF-8(和Unicode)在屏幕或纸上正确呈现非常复杂(因此您需要一些库)。您可能在同一个字符串中混合使用各种语言(英语,俄语,阿拉伯语,中文),其中一些语言正在改变方向。你可能有组合字符(重音符号等)。 Unicode非常复杂(我不太了解它,因为我不懂大多数人类语言;我只会说英语,法语,俄语。我可以破译一些希腊字母。我知道只有极少数的希伯来字母。中文对我来说完全是陌生的。)另请参阅http://utf8everywhere.org/和UTF-8上的Unicode和wikipages。
答案 1 :(得分:3)
C ++标准没有解决正确的UTF8处理问题,但有些库可以通过代码点(实际字符,而不是字节)对字符串进行迭代。
通常,文本存储为字节数组(可能会有一些奇怪的优化,例如tagged pointer strings),并且通常会添加提供正确处理代码点的轻量级string views
。例如,Swift编程语言employs this technique。
至于
或者我可以使用固定长度编码,如UTF-32并使用任何 4字节类型,如unsigned long,用于编码每个UTF-8编码 字符
为方便起见,C ++ 11现在提供std::u8string
,std::u16string
和std::u32string
。在可移植代码中通常应该避免使用std::wstring
,因为wchar_t
的大小是编译器定义的,而不是标准定义的。
答案 2 :(得分:2)
你直截了当地说道。 C ++不代表UTF-8,据我所知它根本不处理它。因此,它只是一种惯例,实际上代表它的是生产和消费UTF-8的那种。
现在正如你所说,UTF-8面向字节,它允许你使用C ++中的工具,如std :: string,它只是一个字节数组。 当然,如果你只是将字符串发送到一个不知道标准的随机库,很多事情都可能出错。这里的一些其他答案中提到的字符串的大小,但更糟糕的是,非ASCII字符很可能导致奇怪的行为,因为这些字符中有多个字节。
现在关于UTF-8的好处是对于所有128个字符(包括所有英文字符)具有相同的表示形式。出于这个原因,如果字符串的生产者不知道UTF-8,但它的消费者确实如此,那么事情仍然会有效。
有许多库已经完成这项工作,它们为UTF-8字符串提供特殊类型,或者将std :: string作为UTF-8字符串读取。标准本身为您提供字符串,每个字符可以是多个字节,例如std::u8string
,std::u16string
和std::u32string
,在UTF-8作为字符的情况下,它们都没有真正有用尺寸因本标准而异。
最后一篇关于这个主题的非常好的文章,它也涵盖了通过网络传递字符串时应该做的事情:The Absoultly minimum every developer must know about unicode