昨天写到《使用多字节字符集的跨平台(PC、Android、IOS、WP)编码/解码方法》中提到服务端使用std::string处理字符串,std::string对多字节字符集支持并非很完善,std::string中的函数没有对多字节字符集进行直接的支持。html
例如直接调用std::string的substr函数,就会致使某些状况下截取的字符串尾部产生非法字符。函数
GB系列多字节字符集基础知识:编码
VC环境下工程设置为多字节字符集,默认使用的是GBK编码,GB23十二、GBK、GB18030,这3个都是中文编码方式,并向下兼容。htm
一、GB2312包含7000多个汉字和字符,GBK包含21000多个,GB18030包含27000多个。blog
二、GBK中的中文字符是双字节来表示的,英文字符是用ASCII码表示的,也就是单字节表示的。字符串
三、GBK编码表中也有英文字符的双字节表示形式,因此英文字母能够有2中GBK表示方式。get
四、GBK编码中的中文字符将其最高位都定成1,英文字符单字节最高位都为0。string
五、当用GBK解码时,若高字节最高位为0,则用ASCII码表解码;若高字节最高位为1,则用GBK编码表解码。class
以上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。
记录,为更好的本身!