NSString在不同字符集下的ASCII碼

在ios中,XCode開發時一直沒理解字符集的關係。一個字符串賦值後,是什麼字符集組成的。我根據每一個字符,分析它的ascii碼,然後得到一些特徵信息。


例如這個字符串"abc美國人123",有英文、漢字和數字。

NSStringEncoding encoding2 = NSUTF8StringEncoding;

NSString *testStr = @"abc美國人123";

for (int i = 0; i < [testStr length]; i++) {
    unichar c = [testStr characterAtIndex:i];

    int bytesLeng = [[testStr substringWithRange:NSMakeRange(i, 1)] lengthOfBytesUsingEncoding:encoding2];

    NSLog(@"testStr[%d]=%@ = %d,%d", i, [testStr substringWithRange:NSMakeRange(i, 1)], c, bytesLeng);
}


輸出結果如下:

2013-07-11 15:43:51.918 demo[2561:13d03] testStr[0]=a = 97,1
2013-07-11 15:43:51.918 demo[2561:13d03] testStr[1]=b = 98,1
2013-07-11 15:43:51.918 demo[2561:13d03] testStr[2]=c = 99,1
2013-07-11 15:43:51.918 demo[2561:13d03] testStr[3]=美 =美
2013-07-11 15:43:51.918 demo[2561:13d03] testStr[3]=美 = 32654,3
2013-07-11 15:43:51.918 demo[2561:13d03] testStr[4]=國 = 22269,3
2013-07-11 15:43:51.919 demo[2561:13d03] testStr[5]=人 = 20154,3
2013-07-11 15:43:51.919 demo[2561:13d03] testStr[6]=1 = 49,1
2013-07-11 15:43:51.919 demo[2561:13d03] testStr[7]=2 = 50,1
2013-07-11 15:43:51.919 demo[2561:13d03] testStr[8]=3 = 51,1


這個字符串是根據默認字符集進行編碼的,英文字符和數字可以很容易看出來,都是按照ASCII字符集進行編碼,但漢字是採用什麼字符集呢?是默認字符集進行編碼的嗎?

我先從操作系統上去思考,是不是採用操作系統默認的字符集。那麼如何得到操作系統的默認字符集呢?

NSString的幫助文檔告訴我,使用defaultCStringEncoding的NSString類方法得到結果值爲30,對應的編碼字符集是 NSMacOSRomanStringEncoding。

這是在XCODE中獲取的。其實它欺騙了我一下。

字符串NSString * testStr=@"abc美國人123";的賦值操作是在一個文件中進行的,字符串的編碼方式應該首先是從文件的編碼上去考慮的。文件的編碼是什麼,字符串就是什麼編碼。
在XCODE中的text encoding是UTF8,事先都設置好的。
其實,這點和eclipse開發工具是一樣的。很多時候,我們在eclipse看到源代碼文件中很多亂碼字符,都是因爲字符集轉換導致的。

因此,在XCODE中,我們看到的字符串的編碼方式就是UTF8。

這個字符串編碼可以做一些轉換操作。需要使用方法- (BOOL)canBeConvertedToEncoding:(NSStringEncoding)encoding,判斷一下這個字符串能不能無丟失轉換到對應的字符集編碼。

因爲有些字符集可以轉到超字符集,但是有些不能轉,有些也不能逆轉。例如GB2312可以轉爲GBK,但是就GBK不能轉到GB2312了。這取決於它的編碼方式。

GB2312是GBK的子集,GBK是GB18030的子集。

UTF- 8:Unicode Transformation Format-8bit,允許含BOM,但通常不含BOM。是用以解決國際上字符的一種多字節編碼,它對英文使用8位(即一個字節),中文使用24爲(三個字節)來編碼。UTF-8包含全世界所有國家需要用到的字符,是國際編碼,通用性強。UTF-8編碼的文字可以在各國支持UTF8字符集的瀏覽器上顯示。如,如果是UTF8編碼,則在外國人的英文IE上也能顯示中文,他們無需下載IE的中文語言支持包。
GBK是國家標準GB2312基礎上擴容後兼容GB2312的標準。GBK的文字編碼是用雙字節來表示的,即不論中、英文字符均使用雙字節來表示,爲了區分中文,將其最高位都設定成1。GBK包含全部中文字符,是國家編碼,通用性比UTF8差,不過UTF8佔用的數據庫比GBD大。
GBK、GB2312等與UTF8之間都必須通過Unicode編碼才能相互轉換:
GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312

在從互聯網上獲取到數據流時需要根據不同的字符集NSUTF8StringEncoding、CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)、NSMacOSRomanStringEncoding 進行轉換操作。


 NSStringEncoding encodings[] = {NSUTF8StringEncoding, CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000),NSMacOSRomanStringEncoding};
    
    for (int k = 0; k < 3; k++) {
        BOOL canEncode = [testStr canBeConvertedToEncoding:encodings[k]];

        NSLog(@"  encode \"%@\" using encoding %X", testStr, encodings[k]);

        if (!canEncode) {
            NSLog(@"    Can not encode \"%@\" using encoding %X", testStr, encodings[k]);
        } else {
            NSData *strData = [testStr dataUsingEncoding:encodings[k]];
            NSString *str = [[NSString alloc] initWithData:strData encoding:encodings[k]];

            for (int i = 0; i < [str length]; i++) {
                unichar c = [str characterAtIndex:i];
                int bytesLeng = [[str substringWithRange:NSMakeRange(i, 1)] lengthOfBytesUsingEncoding:encodings[k]];
                NSLog(@"testStr[%d]=%@ = %d,%d", i, [str substringWithRange:NSMakeRange(i, 1)], c, bytesLeng);
            }
        }
    }

輸出結果如下:

2013-07-11 16:21:49.875 demo[3557:13d03]   encode "abc美國人123" using encoding 4
2013-07-11 16:21:49.875 demo[3557:13d03] testStr[0]=a = 97,1
2013-07-11 16:21:49.875 demo[3557:13d03] testStr[1]=b = 98,1
2013-07-11 16:21:49.875 demo[3557:13d03] testStr[2]=c = 99,1
2013-07-11 16:21:49.876 demo[3557:13d03] testStr[3]=美 = 32654,3
2013-07-11 16:21:49.894 demo[3557:13d03] testStr[4]=國 = 22269,3
2013-07-11 16:21:49.894 demo[3557:13d03] testStr[5]=人 = 20154,3
2013-07-11 16:21:49.894 demo[3557:13d03] testStr[6]=1 = 49,1
2013-07-11 16:21:49.895 demo[3557:13d03] testStr[7]=2 = 50,1
2013-07-11 16:21:49.895 demo[3557:13d03] testStr[8]=3 = 51,1

2013-07-11 16:21:49.895 demo[3557:13d03]   encode "abc美國人123" using encoding 80000632
2013-07-11 16:21:49.895 demo[3557:13d03] testStr[0]=a = 97,1
2013-07-11 16:21:49.896 demo[3557:13d03] testStr[1]=b = 98,1
2013-07-11 16:21:49.896 demo[3557:13d03] testStr[2]=c = 99,1
2013-07-11 16:21:49.896 demo[3557:13d03] testStr[3]=美 = 32654,2
2013-07-11 16:21:49.896 demo[3557:13d03] testStr[4]=國 = 22269,2
2013-07-11 16:21:49.896 demo[3557:13d03] testStr[5]=人 = 20154,2
2013-07-11 16:21:49.897 demo[3557:13d03] testStr[6]=1 = 49,1
2013-07-11 16:21:49.897 demo[3557:13d03] testStr[7]=2 = 50,1
2013-07-11 16:21:49.897 demo[3557:13d03] testStr[8]=3 = 51,1


2013-07-11 16:21:49.897 demo[3557:13d03]   encode "abc美國人123" using encoding 1E
2013-07-11 16:21:49.897 demo[3557:13d03]     Can not encode "abc美國人123" using encoding 1E

從結果上可以看到三點:

1、在字符集編碼爲NSUTF8StringEncoding時可以轉換。當然了,本來就是UTF8編碼的。

2、在字符集編碼爲GBK時,也可以。因爲字符是漢字,並且UTF8的編碼範圍比GBK大,所以轉換沒有丟失數據。
3、在字符集編碼爲NSMacOSRomanStringEncoding時,就不行了。

在不同的字符集下,獲取的每一個字符的字節數已經不一樣的,UTF8下漢字三個字節編碼,GBK下是兩個。這點沒有疑問。
有疑問的是,爲什麼獲取的每一個字符的ASCII編碼都是一樣的。

我以漢字"美"爲例,在UTF8下測試獲得ASCII碼的值是15712189,在GBK下獲取的ASCII碼的值是50112。

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