我知道我可以使用mbrtowc()在C语言中遍历多字节字符串。但是如果我想向后迭代怎么办?或者换句话说,我如何找到前一个有效的多字节字符。我尝试了以下方法,并且使用默认的en_us.UTF-8语言环境,它至少部分在我的Ubuntu系统上工作:

        char *str = "\xc2\xa2\xc2\xa1xyzwxfd\xc2\xa9", *tmp = NULL;
        wchar_t wc = 0;
        size_t ret = 0, width = 1;
        mbstate_t state = {0};

        //Iterate through 2 characters using mbrtowc()
        tmp = str;
        tmp += mbrtowc(&wc, tmp, MB_CUR_MAX, &state);
        tmp += mbrtowc(&wc, tmp, MB_CUR_MAX, &state);

        //This is a simplified version of my code. I didnt test this
        //exact code but this general idea did work.
        for(tmp--; (ret = mbrtowc(&wc, tmp, width, &state)) == (size_t)(-1) || ret == (size_t)(-2); width++, tmp--)
            if(width == MB_CUR_MAX) printf("error\n");

        printf("last multibyte character %lc\n", wc);

这个想法很简单,只需向后迭代一个字节,直到找到mbrtowc()定义的有效多字节字符。我的问题是,我可以依靠它来处理任何可能的多字节语言环境,还是仅使用特殊属性进行编码。更具体地说,mbstate_t的使用不正确;我的意思是方向的改变会影响mbstate_t的有效性吗?我能否保证'ret'只能是(size_t)(-1)或(size_t)(-2)而不是因为我目前假设'ret'可能取决于不完整和无效的多字节字符的定义。

最佳答案

如果您需要处理任何理论上可能的多字节编码,则不可能向后迭代。不需要多字节编码具有以下属性,即有效的多字节序列的后缀都不是有效的多字节序列。 (碰巧的是,您的算法需要一个更强的属性,因为您可能会识别出从一个有效序列的中间开始一直到下一个序列的多字节序列。)

另外,如果多字节编码具有移位状态,则无法(通常)再次预测多字节状态。如果备份更改状态的多字节序列,则不知道以前的状态是什么。

UTF-8的设计考虑了这一点。它没有移位状态,并且清楚地标记了可以开始序列的八位字节(字节)。因此,如果您知道多字节编码为UTF-8,则可以轻松地向后迭代。只需向后扫描不在0x80-0xBF范围内的字符。 (UTF-16和UTF-32也很容易在任一方向上进行迭代,但是您需要分别将它们读取为2字节或4字节代码单元,因为未对齐的读取很可能是正确的代码点。)

如果您不知道多字节编码为UTF-8,则根本没有健壮的算法可以向后迭代。您所要做的就是向前迭代并记住每个字符的起始位置和mbstate。

幸运的是,如今,除了Unicode编码外,几乎没有理由支持多字节编码。

关于c - 向后迭代多字节字符串-C,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36671207/

10-11 15:17
查看更多