昨天寫到《使用多字節字符集的跨平台(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。
記錄,為更好的自己!