std::string在多字节字符集环境下substr的实现方法

昨天写到《使用多字节字符集的跨平台(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。


 

记录,为更好的本身!

相关文章
相关标签/搜索