字符串遍历实现的Json原始解析(Objective-C)

字符串遍历实现的Json原始解析(Objective-C)

1. 前言

最近在学习Objective-C(以下简称objc),要做一个Json解析器来巩固一下知识,顺便练练手感。objc的Cocoa库中有一个NSJSONSerialization工具类,用该类的api可以很容易地进行json解析,据说效率还很高。不过,这里我不是用这个类来实现的,而是使用了最原始的字符串遍历的方式来自己进行解析。由于没有很严谨的测试,难免会很容易崩溃或者判断错误之类的,请多海涵。

2. 动手前须知

本次项目的输入是Json字符串(NSString),输出是解析结果(NSDictionary,NSArray或NSString)。如果json格式不正确,会输出Json格式不合法,请检查后重试。

objc中,字符串中读取字符要怎么读?如果只是单纯地使用charAtIndex的话,不同编码格式来读中文时可能会有差错,而且返回的是unichar,不能用来和NSString比较。因此我采用取长度为1的子串来遍历字符串,即类似于这样[inputString substringWithRange: NSMakeRange(index, 1)],这种方式就能准确地取一个字符。

该次实现使用的是递归生成解析对象,即在解析方法的实现中调用自己。主要原因是json中一个对象的value可能是一个对象,这种形式最适合用递归来实现。

3. 流程图

4. 实现

  • 去除特殊符号

输入的json字符串中可能会存在回车符\n,换行符\r 或制表符\t 等,所以我们优先去除这些特殊字符

inputJson = [inputJson stringByReplacingOccurrencesOfString: @"\n" withString: @""]; //去除回车
    inputJson = [inputJson stringByReplacingOccurrencesOfString: @"\r" withString: @""]; //去除换行
    inputJson = [inputJson stringByReplacingOccurrencesOfString: @"\t" withString: @""]; //去除tab
  • 遍历字符串

从这里就算是正式开始解析了,由于本人没有想到要怎么先进行格式验证再进行解析,我选择边解析边验证,解析到不符合json的格式的地方就结束解析。

先从第一个非空格字符开始判断,分为几种可能,{ -> 对象、[ -> 数组、false 、true、null或 " -> 字符串 。需要一一进行判断。

{

我这里先去掉首位的{} 再进行接下来的解析

//先去掉首尾的{},从后往前找,必须先遇到}否则格式错误
for (j = length-1; j > 0; j--) {
    rightChar = [inputJson substringWithRange: NSMakeRange(j, 1)];
    if ([rightChar isEqualToString: @" "]) {
        continue;
    }
    if (![rightChar isEqualToString: @"}"]) {
        return nil;
    } else {
        break;
    }
}
inputJson = [inputJson substringWithRange: NSMakeRange( i+1, j-i-1)];
length = [inputJson length];
i = 0;

然后一个对象可以为空或者必定有一个或多个"key":value (key是任意字符串,value可以是对象、数组、数字、字符串等)这种格式的字符串,否则格式非法。在继续深入遍历之前,我们先定义几个用到的flag

// rightQuote表示key的右引号,leftQuote表示key的左引号,hasColon表示key-value之间的冒号
// firstKeyValue表示是否在找第一对key-value,metComma表示是否已经遇到逗号,foundValue表示找到key之后是否找到对应的value
BOOL rightQuote = NO, leftQuote = NO, hasColon = NO, firstKeyValue = YES, metComma = YES, foundValue = NO;

然后我们深入遍历寻找key

//跳过空格
if ([leftChar isEqualToString: @" "]) {
    continue;
}
//还没遇到左引号之前不能遇到其他字符
if ( (![leftChar isEqualToString: @"\""]) && leftQuote == NO ) {
    //除非是第一个键值对之后的key,其之前可以遇到逗号
    if (!firstKeyValue && [leftChar isEqualToString: @","] && metComma == NO) {
        metComma = YES;
        continue;
    }
    else {
        return nil;
    }
}
//寻到key,非第一对键值对的引号之前必须遇到逗号,已经找到key的话就不需要执行该if语句的方法块
if ([leftChar isEqualToString: @"\""] &&
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值