15

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

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

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

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

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

但是,我该如何做这第一步呢?也就是说,我如何“取消转义”字符串以便拥有一个序列化的 JSON 对象? +[NSJSONSerialization JSONObjectWithData:options:error:]仅当顶级对象是数组或字典时才有效;它不适用于字符串。

我最终编写了自己的 JSON 字符串解析器,我希望它符合RFC 4627 的第 2.5 节。但我怀疑我忽略了一些使用NSJSONSerialization或其他可用方法的简单方法。

4

4 回答 4

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; }
于 2013-06-05T20:01:28.783 回答
0

将字符串转换为数据:

NSString *string = @"{ \"name\" : \"Bob\", \"age\" : 21 }";
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
于 2013-06-05T19:46:10.243 回答
0

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

NSString *sub = [original substringWithRange:(NSRange){ 1, original.length - 2 }];
NSString *unescaped = [sub stringByReplacingOccurrencesOfString:@"\\\" withString:@"\"];
于 2013-06-05T19:51:44.037 回答
-1

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

但无论如何。你得到的字符串似乎是一个转义的JSON。这实际上意味着什么,完全取决于 Web 服务开发人员。我怀疑,只有双引号和转义本身已经被转​​义了\。结果字符串不是“序列化”的——JSON 已经序列化了——而是编码的。为了将其还原-您需要“取消转义”或再次对其进行解码:

一个小小的 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;
}

印刷:

{“姓名”:“鲍勃”,“年龄”:21 }

于 2013-06-05T21:44:23.383 回答