【问题标题】:std::string and UTF-8 encoded unicodestd::string 和 UTF-8 编码的 unicode
【发布时间】:2013-09-11 09:14:44
【问题描述】:

如果我理解得很好,可以同时使用string和wstring来存储UTF-8文本。

  • 对于char,ASCII字符占一个字节,有些汉字占3或4等。这意味着str[3]不一定指向第4个字符。

  • wchar_t 相同,但每个字符使用的最小字节数始终为 2(而不是 char 的 1),3 或 4 字节宽的字符将占用 2 wchar_t

对吗?

那么,如果我想将string::find_first_of()string::compare() 等与如此奇怪的编码字符串一起使用怎么办?它会起作用吗?字符串类是否处理字符具有可变大小的事实?或者我应该只将它们用作无特征的虚拟字节数组,在这种情况下我宁愿使用wchar_t[] 缓冲区。

如果 std::string 不处理,第二个问题:是否有库提供可以处理 UTF-8 编码的字符串类,以便 str[3] 实际上指向第三个字符(这将是一个来自长度的字节数组1到4)?

【问题讨论】:

  • 请注意,即使str[3] 是第四个代码点,也不一定是第四个用户感知字符。
  • @delnan 好吧抱歉(我刚刚挑选了一篇关于 wchar_t、Windows 和 UTF-16 的示例文章)。由于编辑为时已晚,我删除了评论,这里是没有“有争议”链接的部分:我认为wchar_t 的大小是实现定义的,所以不是 总是 2 个字节。此外(IIRC)Windows 使用它来存储 UTF-16 之类的东西,而不是 UTF-8。见en.wikipedia.org/wiki/Wide_character

标签: c++ string unicode utf-8


【解决方案1】:

您在谈论 Unicode。 Unicode 使用 32 位来表示一个字符。然而,由于这是浪费内存,所以有更紧凑的编码。 UTF-8 就是这样一种编码。它假定您使用的是字节单位,并将 Unicode 字符映射到 1、2、3 或 4 个字节。 UTF-16 是另一种使用单词作为单位并将 Unicode 字符映射到 1 或 2 个单词(2 或 4 个字节)的方法。 您可以将两种编码与字符串和 wchar_t 一起使用。对于英文文本/数字,UTF-8 往往更紧凑。

无论使用何种编码和类型(比较),有些事情都会起作用。然而,所有需要理解一个字符的功能都将被破坏。即第 5 个字符并不总是底层数组中的第 5 个条目。它可能看起来像是在使用某些示例,但它最终会崩溃。 string::compare 会起作用,但不要指望按字母顺序排列。那是依赖于语言的。 string::find_first_of 将适用于某些但不是全部。长字符串可能会因为它们很长而起作用,而较短的字符串可能会被字符对齐混淆并产生很难找到的错误。

最好的办法是找到一个可以为您处理它的库并忽略下面的类型(除非您有充分的理由选择其中一个)。

【讨论】:

  • 感谢您的回答。
  • Unicode 使用 32 位来表示一个字符。 => 真的取决于你所说的字符。 Unicode 定义了 Code Points(整数)和 Graphemes(整数序列,通常大小为 1),人们倾向于将“字符”与“字素”联系起来,因为它是出现在屏幕上的视觉实体。
  • Unicode 使用 32 位来表示一个字符。 这是不正确的! Unicode 确实使用任何数量的位来表示一个字符。 Unicode 纯粹是抽象的。它为每个字符分配一个数字。它不要求用多少位来表示该字符。编码不是表示字符的“更紧凑”的方式,它们表示字符的方式。见joelonsoftware.com/2003/10/08/…
【解决方案2】:

您无法使用 std::string 或标准库中的任何其他工具处理 Unicode。使用外部库如:http://utfcpp.sourceforge.net/

【讨论】:

  • 谢谢,我去看看。
【解决方案3】:

你说得对:
...这意味着 str[3] 不一定指向第 4 个字符...仅将它们用作无特征的虚拟字节数组...

C++ 的字符串只能处理 ascii 字符。这与 Java 的 String 不同,后者可以处理 Unicode 字符。可以将汉字的编码结果(字节)存入字符串(C/C++中的char就是字节),但这没有意义,因为字符串只是把字节当作ascii字符,所以不能用字符串函数来处理。
wstring 可能是你需要的。

有一点需要澄清。 UTF-8 只是 Unicode 字符的一种编码方法(将字符从/转换为字节格式)。

【讨论】:

  • 感谢您的回答。我想知道的是,当使用 UTF-8 编码的文本时,字符串类的哪些方法仍然有效。
  • -1 std::string 存储 chars。但这并不意味着它仅限于 ASCII,它只是意味着它对编码一无所知,所以你可以将它用于任何编码(如果你不小心,就会搞砸一切)。而Java的字符串是一个UTF-16数组,所以str[3]也不一定是第四个码位。
  • @delnan 请在完全通过我的回答后投反对票。我已经说过“您可以将汉字的编码结果(字节)存储到字符串中(C / C ++中的char只是字节),但这没有意义,因为字符串只是将字节视为ascii字符,因此您不能使用字符串函数处理它。”我说“C++的字符串只能处理ascii字符。”不是“C++ 字符串只能存储 ascii 字符。” HANDLE 与 STORE 不同。当您仅使用它来存储字节时,字符串函数将毫无意义,这就是我使用 HANDLE 的原因。谢谢。
  • 恐怕您必须详细说明“store”和“handle”之间的区别,因为我找不到任何适用于 ASCII 但不适用于 UTF-8 编码字符串的操作(UTF-16 可能是另一回事) - 子字符串搜索,例如,works just fine。索引、迭代或选择子字符串将使用代码单元而不是代码点,但您声称处理 Unicode 的 Java 字符串也是如此。
  • @delnan 实际上字符串的 substr 不是搜索,只是对 ascii 字符或换句话说字节的操作。 string::find 可以使用 UTF-8 编码的字符串吗?例如使用 string::find 在一个存储 UTF-8 编码字节的字符串中查找中文/日文字符。显然,它不能工作。这就是我使用 HANDLE 而不是 STORE 的原因。我真的很难理解为什么您在完成我的答案之前对我的答案投了反对票并给出了这样的 cmets。当然,HANDLE 不够准确,但我意识到这一点并在这句话之后进行了详细说明。
猜你喜欢
  • 2013-09-26
  • 1970-01-01
  • 2018-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-03
  • 2013-05-11
相关资源
最近更新 更多