2009-08-29 13 views
15

Podczas odczytu NSString z pliku mogę użyć initWithContentsOfFile:usedEncoding:error: i odgadnę kodowanie pliku.Odgadnij kodowanie podczas tworzenia NSString z NSData

Kiedy tworzę go z NSData, ale moją jedyną opcją jest initWithData:encoding:, gdzie muszę jawnie przekazać kodowanie. Jak mogę niezawodnie odgadnąć kodowanie, gdy pracuję z NSData zamiast plików?

Odpowiedz

12

Ogólnie rzecz biorąc, nie można. Można jednak dość wiarygodnie zidentyfikować pliki UTF-8 - jeśli plik jest poprawny UTF-8, nie jest bardzo prawdopodobne, że ma to być jakiekolwiek inne kodowanie (z wyjątkiem sytuacji, gdy wszystkie bajty znajdują się w zakresie ASCII, w takim przypadku dowolne ". rozszerzone kodowanie ASCII, w tym UTF-8, da taki sam wynik). Wszystkie kodowania Unicode mają również opcjonalny BOM, który je identyfikuje. Tak więc rozsądne podejście byłoby następujące:

  • Poszukaj prawidłowego BOM. Jeśli takowy istnieje, użyj odpowiedniego kodowania.
  • W przeciwnym razie spróbuj interpretować je jako UTF-8. Możesz to zrobić, dzwoniąc pod numer initWithData:data encoding:NSUTF8StringEncoding i sprawdzając, czy wynik nie jest zerowy.
  • Jeśli to się nie powiedzie, użyj domyślnego 8-bitowego kodowania, takiego jak -[NSString defaultCStringEncoding] (która zapewnia trafne domysły).

To jest można spróbować poprawić przypuszczenie W ostatnim kroku, próbując różnymi kodowanie i wybiera ten, który ma najmniejszą liczbę sekwencji liter ze śmieciami w środku, gdzie „śmieci” oznacza dowolny znak, że to nie jest to litera, spacja ani wspólny znak interpunkcyjny. Zwiększyłoby to znacznie złożoność, a jednocześnie nie byłoby niezawodne.

Krótko mówiąc, aby móc obsłużyć wszystkie dostępne kodowania, musisz wykonać polecenie TextEdit: zablokować decyzję użytkownikowi.

Aha, jeszcze jedno: od 10.5 kodowanie jest często przechowywane z plikiem w nieudokumentowanym rozszerzonym atrybucie com.apple.TextEncoding. Jeśli otworzysz plik o numerze +[NSString stringWithContentsOfFile:] lub podobnym, zostanie on automatycznie użyty, jeśli jest obecny.

23

w iOS 8 i OS X 10.10 pojawił się nowy interfejs API na 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 

Teraz możesz pozwolić ramy zgadywać i z mojego doświadczenia, że ​​działa naprawdę dobrze!

z nagłówka (dokumentacja nie określa metodę w tej chwili, ale to było oficjalnie wymienione w WWDC Session 204 (page 270):

  1. tablicą sugerowanych kodowania string (bez określania 3rd opcję na liście, rozważane są wszystkie kodowania ciągów znaków, ale te w tablicy będą miały wyższą preferencję, ponadto kolejność kodowań w tablicy jest ważna: pierwsze kodowanie ma wyższą preferencję niż druga w tablicy). kodowania ciągów nie używać (kodowania ciągów na tej liście nie będzie c onsidered w ogóle)
  2. logiczną opcja wskazuje, czy tylko je kodowania smyczkowe są uważane
  3. logiczną opcję wskazującą, czy stratny jest dozwolone
  4. opcja, która daje konkretny ciąg substitude do tajemnicy bajty
  5. prąd język autora
  6. logiczną opcja wskazuje, czy dane są generowane przez system Windows

Jeśli wartości w słowniku mają złe typy (na przykład wartość KSW tringEncodingDetectionSuggestedEncodingsKey nie jest tablicą), zgłoszony wyjątek.

Jeśli wartości w słowniku są nieznane (na przykład wartość w tablicy sugerowanych kodowań ciągów nie jest prawidłowym kodowaniem), wartości zostaną zignorowane.

Przykład (Swift):

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

Jeśli chcesz tylko zdekodowany ciąg i nie dbają o kodowaniu można usunąć let encoding =

+0

Wydaje się, że jest powód, dlaczego jest jeszcze nie oficjalne. Uruchomiłem go za pomocą pliku NSData PDF, który powraca - 2147482362. – FireDragonMule

+0

Nie jestem do końca pewien, czy tak ma działać. Plik pdf nie jest ciągiem znaków i ta metoda wykrywa kodowanie ciągów z 'NSData'. Jaki jest twój zamiar? – HAS

+0

Pobieram plik pdf przez SDK jako NSData. Mam tylko problemy z wyświetlaniem go w widoku strony teraz, ponieważ nie wiem, co to jest kodowanie lub czy istnieje kodowanie. – FireDragonMule