【问题标题】:std::string optimal way to truncate utf-8 at safe placestd::string 在安全位置截断 utf-8 的最佳方法
【发布时间】:2016-02-11 00:13:09
【问题描述】:

我在 std::string 中有一个有效的 utf-8 编码字符串。我有字节限制。我想截断字符串并在MAX_SIZE - 3 - x 处添加... - 其中x 是防止utf-8 字符被剪切的值。

是否有函数可以根据 MA​​X_SIZE 确定 x 而无需从字符串的开头开始?

【问题讨论】:

    标签: c++ string utf-8


    【解决方案1】:

    如果您在字符串中有一个位置,并且您想向后查找 UTF-8 字符的开头(因此是一个有效的剪切位置),这很容易做到。

    您从序列中的最后一个字节开始。如果最后一个字节的前两位是10,那么它是 UTF-8 序列的一部分,所以继续备份直到前两位 not 10(或者直到你到达起点)。

    UTF-8 的工作方式是,根据字节的高位,一个字节可以是三件事之一。如果最高位是0,则该字节是 ASCII 字符,接下来的 7 位是 Unicode 代码点值本身。如果最高位是10,那么后面的 6 位是多字节序列的额外位。但是多字节序列的开头在前 2 位用11 编码。

    所以如果一个字节的最高位不是10,那么它要么是一个ASCII字符,要么是一个多字节序列的开始。无论哪种方式,它都是一个有效的切割位置。

    但是请注意,虽然此算法会在代码点边界处破坏字符串,但它会忽略 Unicode 字形簇。这意味着可以剔除组合字符,远离它们组合的基本字符;例如,重音可能会从字符中丢失。进行正确的字素聚类分析需要访问 Unicode 表,该表说明代码点是否是组合字符。

    但它至少是一个有效的 Unicode UTF-8 字符串。所以这比大多数人做的要好;)


    代码看起来像这样(在 C++14 中):

    auto FindCutPosition(const std::string &str, size_t max_size)
    {
      assert(str.size() >= max_size, "Make sure stupidity hasn't happened.");
      assert(str.size() > 3, "Make sure stupidity hasn't happened.");
      max_size -= 3;
      for(size_t pos = max_size; pos > 0; --pos)
      {
        unsigned char byte = static_cast<unsigned char>(str[pos]); //Perfectly valid
        if(byte & 0xC0 != 0x80)
          return pos;
      }
    
      unsigned char byte = static_cast<unsigned char>(str[0]); //Perfectly valid
      if(byte & 0xC0 != 0x80)
        return 0;
    
      //If your first byte isn't even a valid UTF-8 starting point, then something terrible has happened.
      throw bad_utf8_encoded_text(...);
    }
    

    【讨论】:

    • 实际上,UTF-8 编码的字节模式是这样的,很容易确定下一个字符开始的边界。
    • 我知道数据 - 我只是不想从乞求中迭代以找出哪个是截断的 /if any/ 字符
    • 问题是我能确定我所在的角色从哪里开始。
    • 这将允许在代码点边界处截断字符串,但它可能会更改字符串中的字符,而不仅仅是将它们截断。例如。这可能会导致“resume”变成“resume”。
    • @bames53:平心而论,剪切字符可以将任何单词变成废话。 “haai”到“haa”在语法上同样错误,只是用荷兰语而不是法语。 (不能有后缀-aa)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 2013-09-11
    相关资源
    最近更新 更多