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。


 

记录,为更好的自己!

 

posted @ 2015-01-28 20:01  全栈工程狮  阅读(1975)  评论(2编辑  收藏  举报