:前言 造車輪的時候要用到中文字元串的長度辨別,發現char的識別不准,進行了一番研究。 > 開始研究 在Windows下,中文字元在C++中的記憶體占用為2位元組,此時採用字元串長度獲取函數得到的結果會將一個中文字元識別為兩個長度: #include <stdio.h> #include <strin ...
:前言
造車輪的時候要用到中文字元串的長度辨別,發現char的識別不准,進行了一番研究。
> 開始研究
在Windows下,中文字元在C++中的記憶體占用為2位元組,此時採用字元串長度獲取函數得到的結果會將一個中文字元識別為兩個長度:
#include <stdio.h>
#include <string>
using namespace std;//string在std命名空間中
int main()
{
string str = "abc中文def";
printf("字元串為:%s\n", str.data());//data()函數回傳字元串的指針,與c_str()相同
int len;
char str1[50];
strcpy(str1, str.data());//賦值
len = strlen(str1);
printf("字元串的長度為(%d)\n", len);
//使用strlen函數獲取長度
string str2 = str;//也可以用string str2.assign(str),這是string的賦值函數,不過和=沒區別
len = str2.length();//也可以用len = str2.size();
printf("字元串的長度為(%d)\n", len);
//使用string類的長度獲取函數length()
system("pause");
}
點擊查看輸出
字元串為:abc中文def
字元串的長度為(10)
字元串的長度為(10)
請按任意鍵繼續. . .
而實際上,字元串的長度為8,並非上述方法的結果10。那麼,如何獲取真正的長度呢?
>> 上手嘗試
其實,我們不妨試試中文字元的值:
char a = '中';
char b = '文';
char c = '字';
char d = '符';
printf("字元‘中’在編碼中的值為%d\n",(int)a);
printf("字元‘文’在編碼中的值為%d\n",(int)b);
printf("字元‘字’在編碼中的值為%d\n",(int)c);
printf("字元‘符’在編碼中的值為%d\n",(int)d);
system("pause");
點擊查看輸出
字元‘中’在編碼中的值為-48
字元‘文’在編碼中的值為-60
字元‘字’在編碼中的值為-42
字元‘符’在編碼中的值為-5
請按任意鍵繼續. . .
試試其他中文字元,也都是負數。
>> 總結歸納
依據這一點,我們便可以做出一個獲取含有中文的字元串長度的函數:
string版:
int getLength_str(string str)
{
int count = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] < 0) i++;
//負數說明該字元為中文字元,占用兩個位元組,跳過後一個位元組(i++),不進行統計
count++;
}
return count;
}
char版: 雖然char數組也可以傳入上面的函數,不過為了避免某些奇葩編譯器,還是再寫了一個函數,即拷即用:
int getLength_char(char str[])
{
int count = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] < 0) i++;
count++;
}
return count;
}
不過,char版不可以傳string。
>> 試驗驗證
用前面的示例驗證:
點擊查看代碼
#include <stdio.h>
#include <string>
using namespace std;
int getLength_str(string str)
{
int count = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] < 0) i++;
//負數說明該字元為中文字元,占用兩個位元組,跳過後一個位元組(i++),不進行統計
count++;
}
return count;
}
int getLength_char(char str[])
{
int count = 0;
for (int i = 0; str[i]; i++)
{
if (str[i] < 0) i++;
count++;
}
return count;
}
int main()
{
string str = "abc中文def";
printf("字元串為:%s\n", str.data());//data()函數回傳字元串的指針,與c_str()相同
int len;
char str1[50];
strcpy(str1, str.data());//賦值
len = strlen(str1);
printf("字元串的長度為(%d)\n", len);
//使用strlen函數獲取長度
len = getLength_char(str1);//len = getLength_str(str1);
printf("字元串的長度為[%d]\n", len);
//用上面的函數獲取含有中文字元的字元串的真正長度
string str2 = str;//也可以用string str2.assign(str),這是string的賦值函數,不過和=沒區別
len = str2.length();//也可以用len = str2.size();
printf("字元串的長度為(%d)\n", len);
//使用string類的長度獲取函數length()
len = getLength_str(str2);
printf("字元串的長度為[%d]\n", len);
//用上面的函數獲取含有中文字元的字元串的真正長度
system("pause");
}
點擊查看輸出
字元串為:abc中文def
字元串的長度為(10)
字元串的長度為[8]
字元串的長度為(10)
字元串的長度為[8]
請按任意鍵繼續. . .
這個函數也可以獲取沒有中文字元的字元串長度.
總結
通過對中文字元數值的輸出,從而找到char數組對中文字元串的長度處理解決方法。
當然處理中文字元串最好的方法是轉換成寬位元組,但會比較麻煩。
另外,新版的C++20string
好像已經解決了這個長度問題。這篇文是之前在CSDN寫的,當時是不可以的。
另:
字元串轉寬位元組後,採用wcslen(wchar_t*)
方法可以準確的讀出寬位元組字元串的字元數(畢竟寬位元組就是為了這事專門設計的)
The End
Yuito 2023