Угадай кодировку при создании NSString из NSData - PullRequest
17 голосов
/ 29 августа 2009

При чтении NSString из файла я могу использовать initWithContentsOfFile:usedEncoding:error:, и он будет угадывать кодировку файла.

Когда я создаю его из NSData, мой единственный вариант - initWithData:encoding:, где я должен явно передать кодировку. Как я могу надежно угадать кодировку при работе с NSData вместо файлов?

Ответы [ 2 ]

26 голосов
/ 04 ноября 2014

В iOS 8 и OS X 10.10 есть новый API на 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

Теперь вы можете позволить фреймворку делать предположения, и, по моему опыту, это работает очень хорошо!

Из заголовка (в документации не указывается метод на данный момент, но он был официально упомянут в WWDC Session 204 (стр. 270) :

  1. массив предлагаемых строковых кодировок (без указания третьей опции в этом списке рассматриваются все строковые кодировки, но у тех, которые находятся в массиве, будет более высокий приоритет; кроме того, важен порядок кодировок в массиве: первое кодирование имеет более высокое предпочтение, чем второе в массиве)
  2. массив строковых кодировок, которые не следует использовать (строковые кодировки в этом списке не будут рассматриваться вообще)
  3. логическая опция, указывающая, считаются ли только предложенные кодировки строк
  4. логическая опция, указывающая, разрешено ли с потерями
  5. опция, которая дает конкретную строку для замены загадочных байтов
  6. язык текущего пользователя
  7. логическая опция, указывающая, генерируются ли данные в Windows

Если значения в словаре имеют неправильные типы (например, значение NSStringEncodingDetectionSuggestedEncodingsKey не является массивом), создается исключение.

Если значения в словаре неизвестны (например, значение в массиве предложенных кодировок строк не является допустимой кодировкой), значения будут игнорироваться.

Пример (Swift):

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

Если вы просто хотите расшифровать строку и не заботитесь о кодировке, вы можете удалить let encoding =

12 голосов
/ 29 августа 2009

В общем, вы не можете. Однако вы можете достаточно надежно идентифицировать файлы UTF-8 - если файл является допустимым UTF-8, маловероятно, что это будет какая-либо другая кодировка (кроме случаев, когда все байты находятся в диапазоне ASCII, в этом случае любой « расширенное кодирование ASCII », включая UTF-8, даст тот же результат). Все кодировки Unicode также имеют опциональную BOM , которая их идентифицирует. Таким образом, разумный подход будет:

  • Ищите действительную спецификацию. Если есть, используйте соответствующую кодировку.
  • В противном случае попробуйте интерпретировать его как UTF-8. Вы можете сделать это, позвонив по номеру initWithData:data encoding:NSUTF8StringEncoding и проверив, если результат не ноль.
  • Если это не помогло, используйте 8-битную кодировку по умолчанию, например -[NSString defaultCStringEncoding] (которая обеспечивает предположение, соответствующее локали).

В можно попытаться улучшить предположение на последнем шаге, попробовав различные кодировки и выбрав ту, которая имеет наименьшее количество последовательностей букв с мусором в середине, где «мусор» - любой символ это не буква, пробел или знак препинания. Это значительно увеличит сложность, хотя на самом деле не будет надежным.

Короче говоря, чтобы иметь возможность обрабатывать все доступные кодировки, вам нужно сделать то, что делает TextEdit: передать решение пользователю.

О, еще одна вещь: с 10.5 кодировка часто сохраняется с файлом в недокументированном расширенном атрибуте com.apple.TextEncoding. Если вы откроете файл с +[NSString stringWithContentsOfFile:] или подобным, он будет автоматически использован, если присутствует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...