c - 向后迭代多字节字符串 - C

标签 c c99 multibyte

我知道我可以使用 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 也可以轻松地在任一方向上迭代,但您需要分别将它们读取为两字节/四字节代码单元,因为未对齐的读取很可能是正确的代码点。)

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

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

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

相关文章:

c - 将不同类型的指针分配给现有内存

c - 如何使用 C99 实现和共享内联函数?

在C99模式下给出编译错误的代码

c - gcc 在调用 `mbtowc()` 时如何决定宽字符集?

c - GCC优化错失良机

c - 从客户端向服务器发送一个字符串

c - Getrusage 内联汇编

c - 数组数组的指定初始化器

php - (铂) 字符串函数和 php 中的 UTF8

ruby-on-rails-3 - 保存到数据库时 JSON 中的多字节字符丢失