【问题标题】:Utf-8 in c++: quick & dirty tricksc++ 中的 utf-8:快速而肮脏的技巧
【发布时间】:2010-12-02 18:00:17
【问题描述】:

我知道有很多关于 utf-8 的问题,主要是关于库来操作 utf-8 'string' 之类的对象。

但是,我正在从事一个“国际化”项目(一个网站,我在其中编写了一个 c++ 后端......别问了),即使我们处理 utf-8,我们实际上也不需要这样的库.大多数情况下,普通的 std::string 方法或 STL 算法足以满足我们的需求,这确实是首先使用 utf-8 的目标。

所以,我在这里寻找的是 "Quick & Dirty" 技巧的大写,您知道与存储为 std::string 的 utf-8 相关(没有 const char*,我真的不关心 c 风格的代码,我有比不断担心缓冲区大小更好的事情要做。

例如,这里有一个 “Quick & Dirty” 技巧来获取字符数(这有助于了解它是否适​​合您的显示框):

#include <string>
#include <algorithm>

// Let's remember than in utf-8 encoding, a character may be
// 1 byte: '0.......'
// 2 bytes: '110.....' '10......'
// 3 bytes: '1110....' '10......' '10......'
// 4 bytes: '11110...' '10......' '10......' '10......'
// Therefore '10......' is not the beginning of a character ;)

const unsigned char mask = 0xC0;
const unsigned char notUtf8Begin = 0x80;

struct Utf8Begin
{
  bool operator(char c) const { return (c & mask) != notUtf8Begin; }
};

// Let's count
size_t countUtf8Characters(const std::string& s)
{
  return std::count_if(s.begin(), s.end(), Utf8Begin());
}

事实上,我还没有遇到过这样的用例,因为我需要字符数以外的任何东西,而且 std::string 或 STL 算法不免费提供,因为:

  • 按预期进行排序
  • 一个词的任何部分都不能混淆为一个词或另一个词的一部分

我想知道您是否还有其他类似的技巧,包括计数和其他简单任务。
我再说一遍,我知道 ICUUtf8-CPP,但我对它们不感兴趣,因为我不需要全面的治疗(事实上我从来不需要超过字符数)。
我还要重申,我对处理 char* 不感兴趣,它们已经过时了。

【问题讨论】:

  • 所以组合变音符号对你来说并不重要?这很可悲。根据您的计数,它们可能是字符,但它们不会占用更多空间。实际上,任何组合字符。或零宽度空格。排序是否按预期工作?你希望做什么?当您故意不使用 Unicode(某种字节数组除外)时,任何特定于语言环境的排序如何知道排序规则。
  • 查看我的编辑,我的应用程序是网站的后端,因此语言环境掌握在浏览器手中。我们还没有遇到过组合字符的问题,我听说过但没见过,你在哪些语言中遇到过?
  • 对非英文文本不起作用的几个用例:排序、大小写折叠、匹配(例如德语 ß 和 ss)。
  • 那么您的意思是,只要您不希望您的 unicode 文本表现得像 unicode,那么如果您不将其视为 unicode,它就会按预期工作?我的,这是一个惊喜。但我为你的非英语用户哭泣。
  • 平心而论,如果您将 UTF-16 或代码点直接存储到 wchar_t 中,则同样会发生忽略组合变音符号的情况。使用 UTF-8 和 char 不会使问题变得更糟。

标签: c++ utf-8


【解决方案1】:

这个肮脏的把戏是行不通的。 首先,这之后的mask是什么值:

   const unsigned char mask = 0x11000000;
   const unsigned char notUtf8Begin = 0x10000000;

也许您正在将十六进制表示与二进制混合。

其次,正如您在 utf-8 编码中正确所说的那样,一个字符可能有几个字节长。 std::count_if 将遍历 UTF8 序列中的所有字节。 但是您真正需要的是查看每个字符的前导字节,然后跳过其余部分,直到下一个字符出现。

实现一个计算并向前跳转的循环并不难 对前导字节使用简单的掩码表。

最后你得到相同的 O(n) 来检查字符,它适用于每个 UTF8 字符串。

【讨论】:

  • 是的,我的面具弄混了,抱歉。然而,除了组合变音符号问题之外,count_if 仍然是正确的。
  • 我正在研究一个 utf8 字符串类,其中 ++ 将正确地遍历宽代码点并放弃从字节跳到字节的偏移数组。它在未来工作得很好,但是对于 - 它没有任何好处。迂腐的代码更容易维护。
【解决方案2】:

将 UTF_8 排序为二进制将不会按“Unicode”顺序排序。 BOCU-1 会。如前所述,您的“预期”对于非英语内容来说是一个相当低的标准。

【讨论】:

    【解决方案3】:

    我们在OpenLieroX 中也是这样处理的(我认为这在游戏中非常好)。

    对于此类 UTF-8 std::strings,我们有一堆有用的函数/算法。请参阅 Unicode.hUnicode.cpp。例如,有 UTF8 迭代器、一些简单的操作运算符(插入或擦除)、大小写转换、大小写无关搜索等。

    但不要期望这些函数总是正确的。例如,他们并不真正了解如何组合变音符号或可能的不同方式来编码相同的文本。

    【讨论】:

      猜你喜欢
      • 2010-09-11
      • 1970-01-01
      • 1970-01-01
      • 2010-10-08
      • 2010-11-11
      • 1970-01-01
      • 2012-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多