How can you deserialize an escaped JSON string wit

2020-01-29 06:24发布

I have an iOS app that needs to process a response from a web service. The response is a serialized JSON string containing a serialized JSON object, looking something like this:

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

Note that this response is a JSON string, not a JSON object. What I need to do is deserialize the string, so that I get this:

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

And then I can use +[NSJSONSerialization JSONObjectWithData:options:error:] to deserialize that into an NSDictionary.

But, how do I do that first step? That is, how to I "unescape" the string so that I have a serialized JSON object? +[NSJSONSerialization JSONObjectWithData:options:error:] only works if the top-level object is an array or a dictionary; it doesn't work on strings.

I ended up writing my own JSON string parser, which I hope conforms to section 2.5 of RFC 4627. But I suspect I've overlooked some easy way to do this using NSJSONSerialization or some other available method.

4条回答
【Aperson】
2楼-- · 2020-01-29 06:50

Convert the string to data:

NSString *string = @"{ \"name\" : \"Bob\", \"age\" : 21 }";
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
查看更多
Animai°情兽
3楼-- · 2020-01-29 06:51

If you have nested JSON, then just call JSONObjectWithData twice:

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; }
查看更多
你好瞎i
4楼-- · 2020-01-29 07:02

One should first ask, why the server just don't include the JSON, as a sub structure.

But anyway. The string you got seems to be an escaped JSON. What that actually means, is totally up to the web service developer. I suspect, that just the double quotes and an escape itself have been escaped with an escape \. The resulting string is not "serialized" - JSON is already serialized - but encoded. In order to revert it back - you need to "unescape" or decode it again:

A little C++ snippet shows how (I know you asked for Objective-C -- but this is just too easy):

Edit: the code should also work for UTF-16 and UTF-32 -- with any endianness - and if the encoder just mechanically did what I suspect, it should also work for escaped unicode characters, e.g. \u1234 etc.

Edit - no, it won't work for UTF-16 and UTF-32. The sample would have to be fixed for that (which would be easy). But please ensure you have UTF-8 - which is almost always the case.

#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;
}

Prints:

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

查看更多
够拽才男人
5楼-- · 2020-01-29 07:04

Just cut off the leading and trailing quotes and then replace all \"s with ":

NSString *sub = [original substringWithRange:(NSRange){ 1, original.length - 2 }];
NSString *unescaped = [sub stringByReplacingOccurrencesOfString:@"\\\" withString:@"\"];
查看更多
登录 后发表回答