文本存储在 std::string
中。
如果文本是8位ASCII码,那么这很容易:
text.pop_back();
但如果它是UTF-8文本呢?据我所知,标准库中没有我可以使用的与UTF-8相关的函数。
如果要使用 UTF-8
,你真的需要一个 UTF-8库。但是对于这个任务,我认为类似这样的东西可能足够了:
void pop_back_utf8(std::string& utf8)
{
if(utf8.empty())
return;
auto cp = utf8.data() + utf8.size();
while(--cp >= utf8.data() && ((*cp & 0b10000000) && !(*cp & 0b01000000))) {}
if(cp >= utf8.data())
utf8.resize(cp - utf8.data());
}
int main()
{
std::string s = "κόσμε";
while(!s.empty())
{
std::cout << s << '\n';
pop_back_utf8(s);
}
}
输出:
κόσμε
κόσμ
κόσ
κό
κ
κόσÄÄμε κόσÄÄμ κόσÄÄ κόσÄA κόσÄ κόσ κό κ
- TayweeUTF-8
,而组合字符似乎是应用程序可能使用的约定。我认为这可能取决于应用程序层面来决定弹出多少代码点以删除给定的字形。 - Galik0xxxxxxx
或11xxxxxx
,所有非前导字节都是10xxxxxx
的形式。这意味着你可以检查第一个和第二个比特位来确定是否有前导字节。bool is_leading_utf8_byte(char c) {
auto first_bit_set = (c & 0x80) != 0;
auto second_bit_set = (c & 0X40) != 0;
return !first_bit_set || second_bit_set;
}
void pop_utf8(std::string& x) {
while (!is_leading_utf8_byte(x.back()))
x.pop_back();
x.pop_back();
}
当然,这并没有进行错误检查,假设您的字符串是有效的utf-8。
first_bit_set
和 second_bit_set
是自动变量,而不是布尔类型? - Iter Atoris_leading_utf8_byte
简化为 return (c & 0xC0) != 0x80
,以测试它是否不是一个尾随字节 (10xxxxxx
)。 - Mark Tolonen
std::basic_string
应该如何帮助?您需要一个UTF库来处理UTF文本编码。 - Lightness Races in Orbit