【c/c++】關於中文字符串的複製切割

    在使用strncpy()函數進行字符串的複製時,有時候會出現這樣的情況:目標字符串的最後一個字符是非法字符,導致寫入數據庫時報錯;

    【以GBK編碼爲例】原因在於一箇中文字符佔兩個字節,假如需要寫入的字符串長度是30,而恰巧第30位和第31位字節存儲的是漢字,這樣就會將漢字編碼切割開來。然後與之後的字符(例如sql中,後面會加一個單引號)進行組合,形成意料之外的中文字符。

    GBK編碼採用雙字節編碼方案,其編碼範圍爲:8140-FEFE,剔除xx7F碼位,共23940個碼位。其中中文字符範圍爲:[0x81-0xFE]。由於漢字是雙字節編碼,如果要滿足該雙字節是漢字的要求的話。則第一個字節範圍必須在0x81-0xFE之間,而第二個字節範圍可以放寬至0x40-0xFE之間。

    如果該字符串是以  '|'【0x7C】   作爲分隔符的話,要滿足該分隔符之前是漢字的要求,前面一個字節的編碼必須在【0x81-0xA0,0xA8-0xFE】之間。因爲【0xA1-0xA7】【0x7C】 該雙字節並不組成漢字。具體規則可參考網址:https://www.qqxiuzi.cn/zh/hanzi-gbk-bianma.php

代碼如下:

void   safe_strncpy(char   dest[], char   source[], int N)
{
	int strlen_source = strlen(source);
	int i = 0, j = 0;
	int flag = 0; /*添加一個標誌,用來標誌所加的中文的位數 */
	unsigned char *p;
	/*N取目標串和N的最小值*/
	if (strlen_source <N)
		N = strlen_source ;

	p = (unsigned char *)source;

	for (i = 0; i<N; i++)   /*N-1用來騰出一位存 '\0 ',字符串數組需要 */
	{
		if (p[i] >= 0x81 && p[i] <= 0xFE) /*中文字符[0x81-0xFE] */
		{
			if ((i + 1) == N)
			{
				/* 前面一半是中文,後面是結束符,捨棄半個漢字*/
				dest[j++] = '\0';
			}
			else
			{
				if (p[i + 1] >= 0x40 && p[i + 1] <= 0xFE)
				{
					if (p[i + 1] == 0x7C && ((p[i]<0x81 && p[i]>0xFE) || (p[i]>0xA0 && p[i]<0xA8)))
					{
						/* 如果是以|爲分隔符的,要滿足前面一半是中文,字節範圍必須在【0X81-0XA0,0XA8-0XFE】之間。如果不在捨棄前面一個 */
						i++;
						dest[j++] = p[i];
					}
					else
					{
						/* 前面一半是中文,後面一半也是中文,說明是一個漢字*/
						dest[j++] = p[i];
						i++;
						dest[j++] = p[i];
					}
				}
				else
				{
					/* 前面一半是中文,後面一半非中文,捨棄前面一個 */
					i++;
					dest[j++] = p[i];
				}
			}
		}
		else
		{
			/* 普通的非中文字符 */
			dest[j++] = p[i];
		}
	}
	dest[j] = '\0';  /*字符串最後賦值結束符*/

	return;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章