代码之家  ›  专栏  ›  技术社区  ›  Matthieu M.

c++中的Utf-8:快速和肮脏的技巧

  •  11
  • Matthieu M.  · 技术社区  · 15 年前

    我知道关于utf-8有各种各样的问题,主要是关于操作utf-8“字符串”类对象的库。

    然而,我正在研究一个“国际化”项目(一个网站,我用它来编码一个C++后端……不要问),即使我们处理UTF-8,我们也不需要这样的库。大多数情况下,普通的std::string方法或STL算法都足以满足我们的需要,事实上,这正是使用utf-8的首要目标。

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

    例如,这里有一个 “快脏” 获取字符数的技巧(了解字符数是否适合显示框很有用):

    #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算法不会免费提供,因为:

    • 分拣工作如期进行
    • 一个词的任何部分都不能与一个词或另一个词的任何部分混淆

    我想知道你们是否有其他类似的技巧,包括计数和其他简单任务。
    我重复一遍,我知道 ICU Utf8-CPP ,但我对它们不感兴趣,因为我不需要一个全面的治疗(事实上,我从来没有需要更多的字符数)。
    我还要重申,我对治疗char*不感兴趣,它们是老式的。

    3 回复  |  直到 15 年前
        1
  •  5
  •   alexkr    15 年前

    这个卑鄙的把戏是行不通的。 首先,在此之后掩码的值是多少:

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

    也许您正在混合十六进制表示法和二进制表示法。

    其次,正如您在utf-8编码中正确地说的,一个字符可能有几个字节长。 但实际上您需要的是查看每个字符的前导字节,并跳过其余部分,直到下一个字符出现。

    要实现一个单独的循环来进行计算并向前跳跃并不困难 对前导字节使用简单掩码表。

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

        2
  •  1
  •   Steven R. Loomis    15 年前

        3
  •  0
  •   Albert    14 年前

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

    对于这样的UTF-8 std::string,我们有一系列有用的函数/算法。看见 Unicode.h Unicode.cpp . 例如,有UTF8迭代器、一些简单的操作操作符(插入或擦除)、大写/小写转换、与大小写无关的搜索等。