Swift 4 base64 String to Data не работает из-за строки, содержащей «неполные» эмодзи - PullRequest
0 голосов
/ 26 сентября 2018

Я пришел из этого поста Swift 4 JSON String с неизвестным символом UTF8 «�» не может быть преобразован в «Данные / словарь» , но в то же время я смог выделить проблему в 10-символьную строку.

Краткое вступление: приложение одного пользователя не показывало никакого контента.Глядя на его 6 КБ данных в виде обычного текста с помощью TextWrangler, я обнаружил 2 красных вопросительных знака

enter image description here.

Я попытался разрезать некоторые куски данных в кодировке base64 вокруг вопросительных знаков и преобразовать их в Данные, которые не работали.Как только я убрал биты из красного вопросительного знака с кусочков, он снова заработал.Пожалуйста, взгляните на мой следующий пример Playground:

//those do NOT work
let toEndBracket = "ACAAKgBVAFMAQQAqACAnlgAg2DwAIgB9AF0A" // *USA* ' <"}]//
let toMidBracket = "ACAAKgBVAFMAQQAqACAnlgAg2DwAIgB9"     // *USA* ' <"}//
let toCarrot =     "ACAAKgBVAFMAQQAqACAnlgAg2DwA"         // *USA* ' <//
let toSpace =      "ACAAKgBVAFMAQQAqACAnlgAg"             // *USA* ' //

//but this one WORKS
let toApostrophe = "ACAAKgBVAFMAQQAqACAn"                 // *USA* '//
//(basically the last one is without the space before the carrot, I've added the slashes after it to emphasize that)
//clear strings taken from https://www.base64decode.org/ using the UTF-8 setting WITHOUT "Live mode".

if let textData = Data(base64Encoded: toApostrophe) {
    print("Data created")   //works for all of them
    print(textData)
    if let decodedString = String(data: textData, encoding: .utf8) {
        print("WORKED!!!")  //only happens for the toApostrophe
        print(decodedString)
    } else {
        print("DID NOT WORK")
    }
}

Так что, в основном, он выходит из строя, как только он содержит lgAg.Замена на что-то вроде U29t заставляет маленькие строки работать снова, но я не могу сделать это в производственном коде, так как я уверен, что мои примеры не единственные случаи возникновения этой проблемы.Мне все равно, что происходит с оригинальными персонажами / символами / смайликами, которые вызывают это, если бы был способ просто «игнорировать» их, который уже был бы более чем полезен!

Вот еще один примергде это происходит:

//OTHER SYMBOL WITH SAME BEHAVIOR
//not working
let secondFromSpace =  "ACDYPAAiACwA"       // <",//

//WORKING
let secondFromCarrot = "PAAiACwA"           //<",//

Вот оригинальный текст в его среде обитания, сообщение посланника с надписью «США» с эмодзи, следовательно, «США» в моих примерах текстов и мое подозрение, что это смайлики, которые делают егоbreak:

enter image description here

Буду признателен, если кто-нибудь скажет мне, как я могу "очистить" строку base64, чтобы она снова могла быть преобразована в данные.Это также может быть связано с какой-то странной кодировкой с некоторыми смайликами, но в большинстве случаев приложение получает и отображает контент с смайликами просто отлично.


Я наконец-то понял, почему это происходит,Это не быстрое решение моей проблемы, но теперь оно имеет хоть какой-то смысл.Для предварительного просмотра нового контента я обрезал строки, чтобы они соответствовали области просмотра браузера.Этот конкретный неудачливый пользователь имел смайлик с флагом США на краю лицевой панели дисплея.Никогда бы я не подумал о смайликах, состоящих из нескольких букв, и о том, что JavaScript substring() их обезглавливает.Взгляните на картинку, это объясняет, откуда происходит этот персонаж и т. Д.

Я все равно был бы признателен за ответ о том, как избежать / игнорировать / поймать это в Свифте, но каждой бедной душе, сталкивающейся с этой проблемой, янадеюсь, что вы наткнетесь на эту тему.

enter image description here

1 Ответ

0 голосов
/ 27 сентября 2018

(Отчасти это из комментариев, но я пытаюсь собрать их вместе и описать решения.)

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

let toApostrophe = "ACAAKgBVAFMAQQAqACAn"                 // *USA* '//
if let textData = Data(base64Encoded: toApostrophe) {
    if let decodedString = String(data: textData, encoding: .utf8) {
        print(decodedString)
        print(decodedString.count)
        print(decodedString.map { $0.unicodeScalars.map { $0.value } } )
    } else {
        print("DID NOT DECODE UTF8")
    }
} else {
    print("DID NOT DECODE BASE64")
}

Отпечатки:

 *USA* '
15
[[0], [32], [0], [42], [0], [85], [0], [83], [0], [65], [0], [42], [0], [32], [39]]

Обратите внимание, что длина строки составляет 15 символов, а не 8, как вы, вероятно, ожидали.Это потому, что он включает в себя дополнительный невидимый NULL (0) между большинством символов. Однако

toEndBracket не является допустимым UTF-8.Вот его байты:

["00", "20", "00", "2a", "00", "55", "00", "53", "00", "41"," 00 "," 2a "," 00 "," 20 "," 27 "," 96 "," 00 "," 20 "," d8 "," 3c "," 00 "," 22 ",«00», «7d», «00», «5d», «00»] ​​

Это нормально, пока не достигнет 0xd8.Это начинается с битов 110, которые указывают, что это начало двухбайтовой последовательности.Но следующий байт 0x3c, который не является допустимым вторым байтом многобайтовой последовательности (он должен начинаться с 10, но начинается с 00).Поэтому мы не можем декодировать это как UTF-8.Даже использование decodeCString(_:as:repairingInvalidCodeUnits) не может декодировать эту строку, потому что она заполнена встроенными значениями NULL.Вы должны декодировать его, используя хотя бы правильную кодировку.

Но давайте сделаем это.Декодировать как UTF-16.По крайней мере, это близко, хотя это слегка недействительный UTF-16.

let toEndBracket16 = String(data: toEndBracketData, encoding: .utf16)
// " *USA* ➖ �"}]"

Теперь мы можем по крайней мере работать с этим.Это неверный JSON, хотя.Таким образом, мы можем убрать это, отфильтровав это:

let legalJSON = String(toEndBracket16.filter { $0 != "\u{FFFD}" })
// " *USA* ➖ "}]"

Я действительно не рекомендую этот подход.Он невероятно хрупок и основан на неправильном вводе.Исправьте ввод.Но в мире, где вы пытаетесь разобрать неверный ввод, это инструменты.

...