如何使用NSJSONSerialization反序列化转义的JSON字符串?

时间:2013-06-05 19:39:55

标签: ios json cocoa nsjsonserialization

我有一个需要处理来自网络服务的响应的iOS应用。响应是一个包含序列化JSON对象的序列化JSON字符串,如下所示:

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

请注意,此响应是JSON 字符串,而不是JSON对象。我需要做的是反序列化字符串,以便我得到这个:

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

然后我可以使用+[NSJSONSerialization JSONObjectWithData:options:error:]将其反序列化为NSDictionary

但是,我该如何做到第一步?也就是说,我如何“unes​​cape”字符串,以便我有一个序列化的JSON对象? +[NSJSONSerialization JSONObjectWithData:options:error:]仅在顶级对象是数组或字典时有效;它不适用于字符串。

我最后写了my own JSON string parser,我希望这符合section 2.5 of RFC 4627。但我怀疑我使用NSJSONSerialization或其他一些可用的方法忽略了一些简单的方法。

4 个答案:

答案 0 :(得分:24)

如果你有嵌套的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; }

答案 1 :(得分:0)

将字符串转换为数据:

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

答案 2 :(得分:0)

只需切断前导和尾随引号,然后将所有\“s替换为”:

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

答案 3 :(得分:0)

首先应该问一下,为什么服务器不包含JSON,作为子结构。

但无论如何。您获得的字符串似乎是转义 JSON。 实际意味着什么,完全取决于Web服务开发人员。我怀疑,只有双引号和一个转义本身已经通过转义\进行了转义。生成的字符串不是“序列化” - JSON已经序列化 - 但编码。为了还原它 - 你需要再次“unes​​cape”或解码

一个小小的C ++代码段显示了(我知道你要求Objective-C - 但这太简单了):

编辑:代码也适用于UTF-16和UTF-32 - 具有任何字节顺序 - 如果编码器只是机械地做了我怀疑的,它也适用于转义的unicode字符,例如\ 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}