向后循环多字节字符串-C



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

        char *str = "xc2xa2xc2xa1xyzwxfdxc2xa9", *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("errorn");
        printf("last multibyte character %lcn", wc);

这个想法很简单,只需向后迭代一个字节,直到我们找到一个由mbrtowc()定义的有效多字节字符。我的问题是,我是否可以依靠它来处理任何可能的多字节区域设置,或者只是使用具有特殊属性的编码。更具体地说,mbstate_t的使用不正确;方向的改变会影响mbstate_t的有效性吗?我可以保证"ret"将仅为(size_t)(-1)或(size_t)(-2),而不是其中之一吗?因为我目前认为"ret"可能同时存在,这取决于不完整和无效多字节字符的定义。

如果您需要处理任何理论上可能的多字节编码,那么就不可能向后迭代。不要求多字节编码具有有效多字节序列的适当后缀都不是有效多字节顺序的特性。(事实上,你的算法需要更强的属性,因为你可能会识别一个多字节序列,从一个有效序列的中间开始,一直到下一个序列。)

此外,如果多字节编码具有移位状态,则无法预测(同样,一般情况下)多字节状态。如果您通过改变状态的多字节序列进行备份,则不知道以前的状态是什么。

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

如果您不知道多字节编码是UTF-8,那么就没有强大的算法可以向后迭代。你所能做的就是向前迭代,记住每个字符的起始位置和mbstate

幸运的是,现在除了Unicode编码之外,几乎没有什么理由支持多字节编码。

对于UTF-8,您可以利用第一个字节后面的附加字节的编码属性:多字节字符的附加字节(并且只有它们)以10xx-xxxx开头。

所以,如果你向后看一个字符c,使(c & 0xC0)==0x80,那么你可以跳过它

对于其他多字节编码,您不一定有一个简单的解决方案,因为前导字节和后续字节在重叠的范围内。

最新更新