语言如何代表UTF-8?

时间:2017-11-23 18:04:19

标签: c++ utf-8 character-encoding

我最近观看了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,这会导致sizelength返回字节长度,但如果UTF-8可以表示不同长度的字符,那怎么做语言(我们将C ++用来限制这个问题的范围)在内部编码这些字符(例如在std::string中)?

3 个答案:

答案 0 :(得分:4)

UTF-8字符串是一些字节序列(即{C}中的char - 或uint8_t)遵循一些限制(因此并非每个字节序列都是有效的UTF-8 string;如果你从外面得到一些声称它是UTF-8的字符串,你应该验证它。)

因此,您可以使用std::string - s来表示UTF-8字符串(前提是您确定它们是有效的UTF-8)。

您可以在其上方使用一些UTF-8库(例如libunistringGlib 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::u8stringstd::u16stringstd::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::u8stringstd::u16stringstd::u32string,在UTF-8作为字符的情况下,它们都没有真正有用尺寸因本标准而异。

最后一篇关于这个主题的非常好的文章,它也涵盖了通过网络传递字符串时应该做的事情:The Absoultly minimum every developer must know about unicode