在开发中,JSON 数据交互非常平凡,行业的标准处理xml就是JSON,但是如果客户使用非标准化的JSON就会出现无法直接从JSON字符转换成JSON对象
标准 JSON
{
"message": {
"list": [
"张三",
"李四'小李'"
],
"info": {
"city": "广州市"
}
},
"other": {
"type": 1,
"var": {}
}
}
当在JSON中key:value 采用 单引号或者没有加引号,在转换对象时会失败。
那么如何避免这个问题呢?
之前在网络上查到很多方法,采用正则表达的方式,先进行JSON字符的格式化,但是始终做不到匹配各种情况下的JSON数据
- (NSString *)changeJsonStringToTrueJsonString:(NSString *)json{
// 将没有双引号的替换成有双引号的
NSString *validString = [json stringByReplacingOccurrencesOfString:@"(\\w+)\\s*:([^A-Za-z0-9_])"
withString:@"\"$1\":$2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [json length])];
//把'单引号改为双引号"
validString = [validString stringByReplacingOccurrencesOfString:@"([:\\[,\\{])'"
withString:@"$1\""
options:NSRegularExpressionSearch
range:NSMakeRange(0, [validString length])];
validString = [validString stringByReplacingOccurrencesOfString:@"'([:\\],\\}])"
withString:@"\"$1"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [validString length])];
//再重复一次 将没有双引号的替换成有双引号的
validString = [validString stringByReplacingOccurrencesOfString:@"([:\\[,\\{])(\\w+)\\s*:"
withString:@"$1\"$2\":"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [validString length])];
return validString;
}
- 有或者以下方式
NSString *responseStr = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
responseStr = [responseStr stringByReplacingOccurrencesOfString:@"'" withString:@"\""];
NSDictionary* dic =[responseStr objectFromJSONString];
if (!dic) { // it's => it"s => it's
responseStr = [responseStr stringByReplacingOccurrencesOfString:@"([A-Za-z0-9_])\"([A-Za-z0-9_])"
withString:@"$1\'$2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [responseStr length])];
dic =[responseStr objectFromJSONString];
}
异常数据
- 存在单引号
"{\"message\": {\"list\": [\"张三\",\"李四'小李'\"],\"info\": {\"city\": \"广州市\"}},\"other\": {'type': 1,'var': {}}}"
- 不存在单引号、双引号
"{message: {\"list\": [\"张三\",\"李四'小李'\",\"i'am iOS\"],\"info\": {\"city\": \"广州市\"}},\"other\": {type: 1,'var': {}}}"
解决方案
为适配以上情况,可以巧妙的使用JS中JSON对象
进行解析,这样可以避免正则表达晦涩难懂,并且不易维护等问题,在 NSJSONSerialization 创建category,每一次json对象化时自动解析,该方案还可以避免使用AFNetworking因为response中JSON对象化不了,直接返回nil
- 具体操作如下:
#import "NSJSONSerialization+Extension.h"
#import <objc/runtime.h>
#import <JavaScriptCore/JavaScriptCore.h>
@implementation NSJSONSerialization (Extension)
+(void)load {
method_exchangeImplementations(class_getClassMethod([self class], @selector(JSONObjectWithData:options:error:)),class_getClassMethod([self class], @selector(myJSONObjectWithData:options:error:)));
}
+ (nullable id)myJSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error
{
if (!data) {
return nil;
}
id object = [self myJSONObjectWithData:data options:opt error:error];
if (object) {
return object;
}
NSString *text = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
if (!data || text.length == 0) {
return nil;
}
JSValue *value = [[[JSContext alloc]init] evaluateScript:[NSString stringWithFormat:@"JSON.stringify(%@)",text]];
NSData *jsonData = [[value toString] dataUsingEncoding:NSUTF8StringEncoding];
object = [self myJSONObjectWithData:jsonData options:opt error:error];
if (object) {
return object;
}
return text;
}
- 测试代码
- (void)test {
NSString *json = @"{message: {\"list\": [\"张三\",\"李四'小李'\",\"i'am iOS\"],\"info\": {\"city\": \"广州市\"}},\"other\": {type: 1,'var': {}}}";
NSData *data = [json dataUsingEncoding:NSUTF8StringEncoding];
id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"object: %@",object);
}
- 测试数据
{
message = {
info = {
city = "\U5e7f\U5dde\U5e02";
};
list = (
"\U5f20\U4e09",
"\U674e\U56db'\U5c0f\U674e'",
"i'am iOS"
);
};
other = {
type = 1;
var = {
};
};
}
result.png
网友评论