我知道我可以使用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);
Run Code Online (Sandbox Code Playgroud)
这个想法很简单,只需向后迭代一个字节,直到找到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编码之外的多字节编码.