std::string在多字节字符集环境下substr的实现方法
昨天写到《使用多字节字符集的跨平台(PC、Android、IOS、WP)编码/解码方法》中提到服务端使用std::string处理字符串,std::string对多字节字符集支持并不是很完善,std::string中的函数没有对多字节字符集进行直接的支持。
例如直接调用std::string的substr函数,就会导致某些情况下截取的字符串尾部产生非法字符。
GB系列多字节字符集基础知识:
VC环境下工程设置为多字节字符集,默认使用的是GBK编码,GB2312、GBK、GB18030,这3个都是中文编码方式,并向下兼容。
1、GB2312包含7000多个汉字和字符,GBK包含21000多个,GB18030包含27000多个。
2、GBK中的中文字符是双字节来表示的,英文字符是用ASCII码表示的,也就是单字节表示的。
3、GBK编码表中也有英文字符的双字节表示形式,所以英文字母可以有2中GBK表示方式。
4、GBK编码中的中文字符将其最高位都定成1,英文字符单字节最高位都为0。
5、当用GBK解码时,若高字节最高位为0,则用ASCII码表解码;若高字节最高位为1,则用GBK编码表解码。
以上5点就可以解释了std::string中substr为什么会在尾部产生非法字符的问题了,substr只考虑了字节长度,没考虑多字节字符集编码。
对于使用substr截断的字符串,在IOS环境下使用NSString初始化时会失败,而Android的String类型则会容忍非法字符。
为了彻底解决平台兼容性问题,必须自己实现截取函数:
int GbkSubString(const char *s, int iLeft) { int len = 0, i = 0; if( s == NULL || *s == 0 || iLeft <= 0 ) return(0); while( *s ) { if( (*s & 0x80) == 0 ) { i ++; s ++; len ++; } else { if( *(s + 1) == 0 ) break; i += 2; s += 2; len += 2; } if( i == iLeft ) break; else if( i > iLeft ) { len -= 2; break; } } return(len); }
先使用GbkSubString函数对长度进行处理,再使用返回的准确长度调用substr。
记录,为更好的自己!