NSAttributedString initWithHTML некорректная кодировка символов?

-[NSMutableAttributedString initWithHTML:documentAttributes:], похоже, приводит в действие специальные символы:

NSString *html = @""Hello" World"; // notice the smart quotes
NSData *htmlData = [html dataUsingEncoding:NSUTF8StringEncoding];
NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithHTML:htmlData documentAttributes:nil];
NSLog(@"%@", as);

Это печатает “Hello†World, за которым следуют некоторые команды RTF. В моем приложении я преобразовываю атрибутированную строку в RTF и отображаю ее в NSTextView, но символы там тоже повреждены.

В соответствии с документацией кодировка по умолчанию - UTF-8, но я попытался быть явным, и результат будет таким же:

NSDictionary *attributes = @{NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]};
NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithHTML:htmlData documentAttributes:&attributes];

Ответы

Ответ 1

Используйте [html dataUsingEncoding:NSUnicodeStringEncoding] при создании NSData и установите соответствующий параметр кодирования при анализе HTML в атрибутной строке:

Документация для NSCharacterEncodingDocumentAttribute немного запутанна:

NSNumber, содержащий int, указывающий NSStringEncoding для файл; для чтения и записи текстовых файлов и написания HTML; по умолчанию для обычного текста используется кодировка по умолчанию; по умолчанию для HTML UTF-8.

Итак, код должен быть:

NSString *html = @""Hello" World";
NSData *htmlData = [html dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                    NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)};
NSMutableAttributedString *as =
    [[NSMutableAttributedString alloc] initWithHTML:htmlData
                                            options: options
                                 documentAttributes:nil];

Ответ 2

Предыдущий ответ здесь работает, но в основном случайно.

Создание NSData с помощью NSUnicodeStringEncoding будет работать, потому что эта константа является псевдонимом для NSUTF16StringEncoding, а UTF-16 довольно легко идентифицировать систему. Проще, чем UTF-8, который, по-видимому, был идентифицирован как какой-либо другой надмножество ASCII (он выглядит как NSWindowsCP1252StringEncoding в вашем случае, вероятно, потому, что он является одним из немногих кодировок на основе ASCII с сопоставлениями для 0x8_ и 0x9 _).

Этот ответ ошибочен в цитировании документации для NSCharacterEncodingDocumentAttribute, потому что "атрибуты" - это то, что вы получаете из -initWithHTML. Вот почему это NSDictionary **, а не только NSDictionary *. Вы можете передать указатель на NSDictionary *, и вы получите ключи, такие как TopMargin/BottomMargin/LeftMargin/RightMargin, PaperSize, DocumentType, UTI и т.д. Любые значения, которые вы пытаетесь пройти через словарь атрибутов, игнорируются.

Вам нужно использовать "параметры" для передачи значений, а соответствующий ключ опции NSTextEncodingNameDocumentOption, который не имеет документального значения по умолчанию. Он передает байты в WebKit для синтаксического анализа, поэтому, если вы не укажете кодировку, предположительно, вы получаете эвристику, кодирующую кодировку WebKit.

Чтобы гарантировать соответствие типов кодирования между вашими NSData и NSAttributedString, вы должны сделать что-то вроде:

NSString *html = @""Hello" World";
NSData *htmlData = [html dataUsingEncoding:NSUTF8StringEncoding];

NSMutableAttributedString *as =
    [[NSMutableAttributedString alloc] initWithHTML:htmlData
                                            options:@{NSTextEncodingNameDocumentOption: @"UTF-8"}
                                 documentAttributes:nil];