在 std::string 中使用非法 UTF-8 八位字节作为分隔符

Posted

技术标签:

【中文标题】在 std::string 中使用非法 UTF-8 八位字节作为分隔符【英文标题】:Using an illegal UTF-8 octet as a delimiter in a std::string 【发布时间】:2019-05-30 16:24:11 【问题描述】:

希望我的问题得到改进和更集中的版本:

由于解释起来会产生误导(见下文),我必须在单个字符串中存储多个 UTF-8 编码字符串。 (这里的字符串表示 C++ std::string

我的方法是将字符串与非法 UTF-8 八位字节(0xC0、0xC1、0xF5-0xFF)之一作为分隔符,因为这些八位字节永远不会出现在有效的 UTF-8 序列中。 (由于 0x00 是一个有效的 UTF-8 八位字节,我认为它不适合我的预期误用。)

除了性能方面的所有考虑之外,我不知道这种方法有什么问题吗?是否有任何理由偏爱其中一个非法八位位组?

..

在我最初的问题中,我试图提供更多背景信息,但这会导致一些关于性能问题和预期权衡的问题。但我的问题不在于这些权衡,而在于我的方法在技术上的可行性和有效性。

【问题讨论】:

@z80crew:“我需要通过索引快速访问单个字符串。”您的数据结构不会发生这种情况。您的 split 函数必须遍历 整个 存储空间 (O(n)) 才能找到第 N 个元素。那不会是“快速访问”。 说实话,我很惊讶这种权衡是值得的。你真的节省了那么多内存吗?同时,您的新字符串 非常非常 更难查找(除非您正在索引它们的起始位置,再次需要更多内存 - 并使分隔符毫无意义,所以我猜不是)!加上修改它们将是一个麻烦。我认为这个问题过于宽泛,无法直接回答,但前提似乎有缺陷。 顺便说一下,"abc" + 0xC0 + "def" + 0xC0 + "ghi" 不是字符串连接,但您可能已经知道并且可能出于说明的目的而忽略它 @z80crew:“对于一些重要的用例,它会产生过多的内存开销”你能澄清一下那些“重要的用例”是什么造成了“过多的内存开销”吗? ? 也使用一些疯狂的非法 UTF-8 序列,使用零 0 作为分隔符更简单、更简洁。 【参考方案1】:

正如其他人所提到的,使用适合您情况的任何字节都可以在std::string 中正常工作。虽然如果您的字符串不使用'\0',那么使用这样的而不是非法的UTF-8 字节可能会更干净。

如果您的实现在速度方面令人满意,那么我想就是这样。否则,您可以研究如何管理数据库。在这种情况下,您将使用固定大小的缓冲区。最大的优点是您不会在许多小块中破坏内存并在以后遇到内存分配问题。同样在速度方面,您将分配这些块一次并多次重复使用它们。 malloc()free() 函数很昂贵,特别是如果您有大量对象(newdelete 运算符调用这些函数。)

现在要节省更多内存,因为这听起来是主要目标,如果可能的话,您可以考虑使用 zlib 压缩字符串。我会使用最快的压缩模式,看看生成的缓冲区是否更小,如果是,请使用它。否则保留未压缩的字符串。这要求您为每个字符串保存一个大小(4 个字节)。缓冲区未压缩时,可以设置大小为0。

我想提到的另一件事是,使用非法字节可能会让未来维护该代码库的程序员感到困惑。无论您有多少 cmets,他们可能无论如何都不会阅读它们......你知道......程序员只是倾向于阅读代码,而不是 cmets。如果这是您担心的事情,您可以将连接的字符串保存在向量中。您的 split 函数将 char 向量作为输入并返回字符串向量作为其结果。

另一种可能性是通过mmap() 使用交换内存。但是,在处理动态数据时,这可能很乏味。这就是类似数据库的方案非常有用的地方。您将分配块(即一次 64Kb)并在每个块的基础上管理您的数据。当一个字符串对于当前块来说变得太大时,将它移动到一个新块......这种技术的优点是数据保留在内存中,除非操作系统决定它需要你的软件正在使用的一些 RAM 并且它可以随时换掉。对你来说,这种交换将是完全透明的。它还比使用默认交换要快得多,默认交换必须以低效率的方式管理您的内存。

【讨论】:

以上是关于在 std::string 中使用非法 UTF-8 八位字节作为分隔符的主要内容,如果未能解决你的问题,请参考以下文章

C++:如何将 std::string 的内容写入 UTF-8 编码文件?

强制对 fmt 中的 std::string 进行 UTF-8 处理

如何将 UTF-8 std::string 转换为 UTF-16 std::wstring?

修复这个 std::async 调用

C++ UTF-8 实际字符串长度

将 std::string 转换为 QString