Подтвердить что ты не робот

Как можно десериализовать escape-строку JSON с помощью NSJSONSerialization?

У меня есть приложение iOS, которое должно обрабатывать ответ от веб-службы. Ответ представляет собой сериализованную строку JSON, содержащую сериализованный объект JSON, выглядящий примерно так:

"{ \"name\" : \"Bob\", \"age\" : 21 }"

Обратите внимание, что этот ответ представляет собой строку JSON, а не объект JSON. Мне нужно сделать десериализацию строки, чтобы получить следующее:

{ "name" : "Bob", "age" : 21 }

И затем я могу использовать +[NSJSONSerialization JSONObjectWithData:options:error:] для десериализации этого в NSDictionary.

Но как мне сделать этот первый шаг? То есть, как я "unescape" строку, так что у меня есть сериализованный объект JSON? +[NSJSONSerialization JSONObjectWithData:options:error:] работает только в том случае, если объект верхнего уровня является массивом или словарем; он не работает с строками.

В итоге я написал мой собственный синтаксический анализатор JSON, который, я надеюсь, соответствует раздела 2.5 RFC 4627. Но я подозреваю, что упустил какой-то простой способ сделать это с помощью NSJSONSerialization или другого доступного метода.

4b9b3361

Ответ 1

Если у вас есть вложенный JSON, просто дважды вызовите JSONObjectWithData:

NSString *string =  @"\"{ \\\"name\\\" : \\\"Bob\\\", \\\"age\\\" : 21 }\"";
// --> the string
// "{ \"name\" : \"Bob\", \"age\" : 21 }"

NSError *error;
NSString *outerJson = [NSJSONSerialization JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding]
                              options:NSJSONReadingAllowFragments error:&error];
// --> the string
//  { "name" : "Bob", "age" : 21 }
NSDictionary *innerJson = [NSJSONSerialization JSONObjectWithData:[outerJson dataUsingEncoding:NSUTF8StringEncoding]
                              options:0 error:&error];
// --> the dictionary
// { age = 21; name = Bob; }

Ответ 2

Преобразование строки в данные:

NSString *string = @"{ \"name\" : \"Bob\", \"age\" : 21 }";
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

Ответ 3

Просто отрежьте передние и конечные кавычки, а затем замените все на ":

NSString *sub = [original substringWithRange:(NSRange){ 1, original.length - 2 }];
NSString *unescaped = [sub stringByReplacingOccurrencesOfString:@"\\\" withString:@"\"];

Ответ 4

Сначала нужно спросить, почему сервер просто не включает JSON, как подструктуру.

Но все равно. Строка, которую вы получили, кажется, сбежала из JSON. То, что это на самом деле означает, полностью зависит от разработчика веб-сервисов. Я подозреваю, что только двойные кавычки и сам побег были спасены с побегом \. Полученная строка не "сериализована" - JSON уже сериализуется, но кодируется. Чтобы вернуть его обратно - вам нужно "unescape" или декодировать его снова:

Небольшой фрагмент С++ показывает, как (я знаю, что вы просили Objective-C - но это слишком просто):

Изменить: код также должен работать для UTF-16 и UTF-32 - с любой точностью - и если кодер просто механически сделал то, что я подозреваю, он также должен работать для экранированных символов юникода, например. \u1234 и т.д.

Изменить - нет, он не будет работать для UTF-16 и UTF-32. Образец должен быть исправлен для этого (что было бы легко). Но, пожалуйста, убедитесь, что у вас есть UTF-8 - это почти всегда так.

#include <iostream>

char input[] = u8R"___({ \"name\" : \"Bob\", \"age\" : 21 })___";

// Unescapes the character sequence "in-situ".
// Returns a pointer to "past-the-end" of the unescaped string.
static char* unescape(char* first, char* last) {
    char* dest = first;
    while (first != last) {
        if (*first == '\\') {
            ++first;
        }
        *dest++ = *first++;
    }
    return dest;
}

int main(int argc, const char * argv[])
{
    char* first = input;
    char* last = first + strlen(input);
    std::string s(input, unescape(first, last));

    std::cout << s << std::endl;

    return 0;
}

Печать

{ "name": "Bob", "age": 21}