C++,linux,如何有效地从字符串中弹出非拉丁字符pop_back()

C++, linux, how to pop_back() efficiently a non latin1 char from a string

本文关键字:丁字符 字符 pop back linux 有效地 字符串 C++      更新时间:2023-10-16

我对string操作有问题,首先考虑这些string s:

string s1 = "Graveworm";
string s2 = "Motörhead"; //the best of the best, just to say...

正如你所看到的,它们每个都有9个char,是的。。但不是…因为当我pop_back()一个像"é"这样重音的字母时,我必须pop_back()两个char秒。

所以现在,有一种方法可以知道我有多少char(s)到pop_back(),记住s1s2写在代码中。

注意:在写这个问题的时候,我想到了一个可能的方法:获取字符串的大小,只要大小没有减少一个,就逐个删除char;嗯,我试过这个:

if(s->size()>0){
         int size = s->size();
         for(i=size; i > size-1 ;i--){
           s->pop_back();
         }

未按预期工作

特别是在现代Linux上,大多数(所有?)文本和代码编辑器将"Motörhead"保存在文件中,引号之间有10个字节。在源代码文件上尝试hexdump,您会看到类似的内容

00000050  32 20 3d 20 22 4d 6f 74  c3 b6 72 68 65 61 64 22  |2 = "Mot..rhead"|

如果您使用u8"Motörhead" ,您可以使用C++11以可移植的方式实现此行为

至于找出每个多字节字符中有多少字节,这几乎没有必要,但如果你真的需要,std::mblen、std::mbrlen和相关函数可以帮助你。

大多数Linux发行版对非ASCII字符使用UTF-8编码。UTF-8的特性是,所有非初始字节都有一个10xxxxxx的位模式,因此可以弹出整个UTF-8字符的一种方式如下:

// Note: How this gets compiled depends on your compiler's input character set.
// For GCC, see the -finput-charset and -fexec-charset compiler options.
std::string s = "Motörhead";
while (s.size() > 0)
{
    char c = s.back();
    s.pop_back();
    // If we found an initial character, we're done
    if ((c & 0xC0) != 0x80)
        break;
}

这是通过弹出字符来实现的,直到我们找到一个初始字符(具有0xxxxxxx11xxxxxx的初始位模式的字符)。它还有一个安全网,可以在您拥有的字符串格式错误且实际上不是有效的UTF-8的情况下拯救和避免Undefined Behavior。

不过,请记住,此代码对其目标环境进行了假设。如果在任何非UTF-8环境中运行此代码,则需要确保在使用此代码之前将字符串转换为UTF-8,并在输出(例如打印到控制台)之前将其转换回目标环境的编码。如果你不能做到这一点,它将以令人惊讶的方式失败(通常是用某种mojibake)。

如果您的编码是UTF-8,您可以利用编码来知道何时到达代码点的第一个字节。当字节值为< 128(ASCII范围)或介于0xc00xff之间时,就会出现这种情况。

不幸的是,当你弹出一个代码点时,这只是告诉你。如果您正在考虑组合字符,则一个实际字符可能由多个代码点组成。