从 std::string 中提取(第一个)UTF-8 字符

Adr*_*ian 4 c++ string utf-8

我需要使用PHP 的 mb_strtoupper 函数C++ 实现来模仿维基百科的行为。

我的问题是,我只想向函数提供一个UTF-8 字符,即 std::string 的第一个字符。

std::string s("äbcdefg");
mb_strtoupper(s[0]); // this obviously can't work with multi-byte characters
mb_strtoupper('ä'); // works
Run Code Online (Sandbox Code Playgroud)

有没有一种有效的方法来检测/返回字符串的第一个 UTF-8 字符?

Adr*_*thy 6

在 UTF-8 中,第一个字节的高位告诉您有多少后续字节是同一代码点的一部分

0b0xxxxxxx: this byte is the entire code point
0b10xxxxxx: this byte is a continuation byte - this shouldn't occur at the start of a string
0b110xxxxx: this byte plus the next (which must be a continuation byte) form the code point
0b1110xxxx: this byte plus the next two form the code point
0b11110xxx: this byte plus the next three form the code point
Run Code Online (Sandbox Code Playgroud)

可以假设该模式继续存在,但我认为有效的 UTF-8 不会使用超过四个字节来表示单个代码点。

如果您编写了一个计算设置为 1 的前导位数的函数,那么您可以使用它来确定在何处拆分字节序列以隔离第一个逻辑代码点,假设输入是有效的 UTF-8。如果您想强化无效的 UTF-8,则必须编写更多代码。

另一种方法是利用连续字节始终匹配 pattern 的事实0b10xxxxxx,因此您获取第一个字节,然后只要下一个字节与该模式匹配就继续获取字节。

std::size_t GetFirst(const std::string &text) {
  if (text.empty()) return 0;
  std::size_t length = 1;
  while ((text[length] & 0b11000000) == 0b10000000) {
    ++length;
  }
  return length;
}
Run Code Online (Sandbox Code Playgroud)

对于许多语言,单个代码点通常映射到单个字符。但是人们所认为的单个字符可能更接近于 Unicode 所谓的字素簇,即一个或多个代码点组合起来产生一个字形。

在您的例子中,ä可以以不同的方式表示:这可能是单码点U+00E4 LATIN SMALL LETTER A WITH DIAERESIS 或者它可能是一个组合U+0061 LATIN SMALL LETTER AU+0308 COMBINING DIAERESIS。幸运的是,只需选择第一个代码点就可以满足您将第一个字母大写的目标。

如果你真的需要第一个字素,你必须超越第一个代码点,看看下一个(s)是否与它结合。对于许多语言,知道哪些代码点是“非间距”或“组合”或变体选择器就足够了。对于一些复杂的脚本(例如,Hangul?),您可能需要查阅这份Unicode Consortium 技术报告


GUI*_*ish 1

文库str.h

\n\n
#include <iostream>\n#include "str.h"\n\nint main (){\n    std::string text = "\xc3\xa4bcdefg";\n    std::string str = str::substr(text, 0, 1); // Return:~ \xc3\xa4\n    std::cout << str << std::endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n