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

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

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

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

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

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

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

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

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

将字符串转换为数据:

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

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

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

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

但不管怎么说。 你得到的字符串似乎是一个转义的 JSON。 实际上意味着什么,完全取决于Web服务开发人员。 我怀疑,只有双引号和逃脱本身已经逃脱了\ 。 结果字符串不是“序列化” – JSON已经序列化 – 但已编码 。 为了还原它 – 你需要“unes​​cape”或再次解码它:

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

编辑:代码也应该适用于UTF-16和UTF-32 – 具有任何字节顺序 – 如果编码器只是机械地做了我怀疑的,它也应该适用于转义的unicode字符,例如\ u1234等。

编辑 – 不,它不适用于UTF-16和UTF-32。 样本必须为此固定(这很容易)。 但请确保您拥有UTF-8 – 几乎总是如此。

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