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。


 

記錄,爲更好的本身!

相關文章
相關標籤/搜索