2009-08-29 36 views
15

當從文件中讀取NSString時,我可以使用initWithContentsOfFile:usedEncoding:error:,它會猜測文件的編碼。從NSData創建NSString時猜測編碼

當我從NSData創建它時,儘管我唯一的選擇是initWithData:encoding:,我必須明確地通過編碼。當我使用NSData而不是文件時,如何可靠地猜出編碼?

回答

12

一般來說,你不能。但是,您可以非常可靠地識別UTF-8文件 - 如果文件的有效性爲UTF-8,則不太可能它應該是任何其他編碼(除非所有字節都在ASCII範圍內,在這種情況下,任何「擴展ASCII「編碼,包括UTF-8,會給你相同的結果)。所有的Unicode編碼也有一個可選的BOM標識它們。因此,合理的做法是:

  • 查找有效的BOM。如果有,使用適當的編碼。
  • 否則,請嘗試將其解釋爲UTF-8。你可以通過調用initWithData:data encoding:NSUTF8StringEncoding並檢查結果是否爲非零來做到這一點。
  • 如果失敗,請使用默認的8位編碼,例如-[NSString defaultCStringEncoding](它提供了適合於區域設置的猜測)。

可能試圖通過嘗試各種不同的編碼,並選擇具有序列最少的信件,垃圾在中間,其中「垃圾」是的任何字符的一個,以提高在最後一步猜不是字母,空格或常見的標點符號。這會顯着增加複雜性,但實際上並不可靠。

簡而言之,爲了能夠處理所有可用的編碼,您需要做TextEdit的工作:將決策分流給用戶。

哦,還有一件事:從10.5開始,編碼通常與文件一起存儲在未記錄的com.apple.TextEncoding擴展屬性中。如果您使用+[NSString stringWithContentsOfFile:]或類似文件打開文件,則會自動使用該文件(如果存在)。

23

在iOS系統中8和OS X 10.10有上NSString一個新的API:

Objective-C的

+ (NSStringEncoding)stringEncodingForData:(NSData *)data 
          encodingOptions:(NSDictionary *)opts 
          convertedString:(NSString **)string 
         usedLossyConversion:(BOOL *)usedLossyConversion; 

斯威夫特

open class func stringEncoding(for data: Data, 
        encodingOptions opts: [StringEncodingDetectionOptionsKey : Any]? = nil, 
       convertedString string: AutoreleasingUnsafeMutablePointer<NSString?>?, 
        usedLossyConversion: UnsafeMutablePointer<ObjCBool>?) -> UInt 

現在你可以讓框架做出猜測,並以我的經驗表現非常出色!

從報頭(文檔沒有說明此刻的方法,但它在WWDC Session 204 (page 270)正式提到:

  1. 建議串編碼的陣列(沒有指定此列表中的第三選項,所有字符串編碼都會被考慮,但陣列中的編碼將具有更高的優先級;此外,陣列中編碼的順序很重要:第一個編碼比第二個編碼具有更高的優先級)
  2. 數組字符串編碼不能使用(這個列表中的字符串編碼不會是c onsidered在所有)
  3. 僅指示所建議的字符串編碼是否被視爲
  4. 指示有損是否允許一個布爾選項布爾選項
  5. ,給出了一個特定的字符串可分別代替用於神祕的選項字節
  6. 當前用戶的語言
  7. 布爾選項指示是否是由Windows

產生的數據。如果在字典中的值有錯誤的類型(例如,NSS的價值tringEncodingDetectionSuggestedEncodingsKey不是數組),拋出異常。

如果字典中的值未知(例如,建議的字符串編碼數組中的值不是有效的編碼),則值將被忽略。

例(SWIFT):

var convertedString: NSString? 
let encoding = NSString.stringEncoding(for: data, encodingOptions: nil, convertedString: &convertedString, usedLossyConversion: nil) 

如果你只是想解碼串並不在乎編碼,您可以刪除let encoding =

+0

好像有就是爲什麼它是有原因的尚未官方。我用它的PDF NSData編碼運行它返回-2147482362。 – FireDragonMule

+0

我不太確定這是否如此。 pdf不是一個字符串,並且此方法從「NSData」中查找字符串的編碼。你的意圖是什麼? – HAS

+0

我正在通過SDK以NSData格式檢索pdf。我只是在webview中顯示問題,因爲我不知道編碼是什麼,甚至是編碼。 – FireDragonMule