2009-08-29 26 views
15

Khi đọc một số NSString từ một tệp, tôi có thể sử dụng initWithContentsOfFile:usedEncoding:error: và nó sẽ đoán mã hóa của tệp.Đoán mã hóa khi tạo một NSString từ NSData

Khi tôi tạo từ NSData mặc dù tùy chọn duy nhất của tôi là initWithData:encoding: nơi tôi phải chuyển mã hóa một cách rõ ràng. Làm thế nào tôi có thể đoán mã hóa một cách đáng tin cậy khi tôi làm việc với NSData thay vì tệp?

Trả lời

12

Nói chung, bạn không thể. Tuy nhiên, bạn có thể nhận dạng các tệp UTF-8 một cách đáng tin cậy - nếu tệp có giá trị UTF-8, không có khả năng là mã hóa khác (trừ khi tất cả các byte nằm trong phạm vi ASCII, trong trường hợp này là “ mã hóa ASCII mở rộng, bao gồm cả UTF-8, sẽ cho bạn kết quả tương tự). Tất cả các bảng mã Unicode cũng có một tùy chọn BOM xác định chúng. Vì vậy, một cách tiếp cận hợp lý sẽ là:

  • Tìm một BOM hợp lệ. Nếu có, hãy sử dụng mã hóa thích hợp.
  • Nếu không, hãy thử diễn giải nó dưới dạng UTF-8. Bạn có thể làm điều này bằng cách gọi số initWithData:data encoding:NSUTF8StringEncoding và kiểm tra xem kết quả có phải là số không.
  • Nếu điều đó không thành công, hãy sử dụng mã hóa 8 bit mặc định, chẳng hạn như -[NSString defaultCStringEncoding] (cung cấp dự đoán phù hợp về vị trí).

thể cố gắng cải thiện đoán ở bước cuối cùng bằng cách cố gắng mã hóa khác nhau khác nhau và chọn một trong đó có chuỗi ít nhất của các chữ cái với rác ở giữa, trong đó “rác” là bất kỳ nhân vật đó là không phải là một chữ cái, dấu cách hoặc dấu chấm câu thông thường. Điều này sẽ làm tăng đáng kể sự phức tạp trong khi không thực sự đáng tin cậy.

Tóm lại, để có thể xử lý tất cả các mã hóa sẵn có, bạn cần phải làm những gì TextEdit làm: shunt quyết định đối với người dùng.

Ồ, một điều nữa: tính đến 10.5, mã hóa thường được lưu trữ với một tệp trong thuộc tính com.apple.TextEncoding mở rộng không có giấy tờ. Nếu bạn mở một tệp có +[NSString stringWithContentsOfFile:] hoặc tương tự, thì tệp này sẽ tự động được sử dụng nếu có.

23

Trong iOS 8 và OS X 10.10 có một API mới trên NSString:

Objective-C

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

Swift

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

Bây giờ bạn có thể cho các khung làm việc đoán và theo kinh nghiệm của tôi hoạt động thực sự tốt!

Từ tiêu đề (tài liệu không ghi rõ phương pháp vào lúc này nhưng nó được chính thức đề cập trong WWDC Session 204 (page 270):

  1. một loạt các mã hóa chuỗi gợi ý (mà không chỉ định tùy chọn thứ 3 trong danh sách này, tất cả các mã hóa chuỗi được xem xét nhưng các mã trong mảng sẽ có sở thích cao hơn; hơn nữa, thứ tự mã hóa trong mảng quan trọng: mã hóa đầu tiên có sở thích cao hơn giá trị thứ hai trong mảng)
  2. một mảng mã hóa chuỗi không sử dụng (mã hóa chuỗi trong danh sách này sẽ không được c onsidered tại tất cả)
  3. một lựa chọn boolean chỉ ra dù chỉ mã hóa chuỗi gợi ý được coi
  4. một lựa chọn boolean chỉ ra cho dù tổn hao được phép
  5. một lựa chọn mà đưa ra một chuỗi cụ thể để substitude cho bí ẩn byte
  6. dòng điện ngôn ngữ của người dùng
  7. một lựa chọn boolean chỉ ra cho dù các dữ liệu được tạo ra bởi Windows

Nếu các giá trị trong từ điển có các loại sai (ví dụ, giá trị của NSS tringEncodingDetectionSuggestedEncodingsKey không phải là một mảng), một ngoại lệ được ném ra.

Nếu các giá trị trong từ điển không xác định (ví dụ: giá trị trong mảng mã hóa chuỗi được đề xuất không phải là mã hóa hợp lệ), các giá trị sẽ bị bỏ qua.

Ví dụ (Swift):

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

Nếu bạn chỉ muốn chuỗi giải mã và không quan tâm đến mã hóa, bạn có thể loại bỏ các let encoding =

+0

Có vẻ như có một lý do tại sao nó là chưa chính thức. Tôi chạy nó với một mã hóa NSData PDF nó trở về-2147482362. – FireDragonMule

+0

Tôi không hoàn toàn chắc chắn nếu đó là cách nó được dự định để làm việc. Một pdf không phải là một chuỗi và phương pháp này tìm mã hóa cho các chuỗi từ một 'NSData'. Ý định của bạn là gì? – HAS

+0

Tôi đang truy xuất bản pdf thông qua SDK dưới dạng NSData. Tôi chỉ gặp sự cố khi hiển thị nó trong chế độ xem web ngay bây giờ vì tôi không biết mã hóa là gì hoặc liệu có mã hóa hay không. – FireDragonMule

Các vấn đề liên quan