实践出真知,对一个技术的理解关键还要看应用和实践。最近在做一个学校的教务系统手机客户端项目,后台那边拿到的数据封装极其恶心,尤其是对时间的封装。在做这个项目的过程中,会用到字符串的查询、切割、拼接,在此拿出来讲一下收获。
需求
背景
先说说需求,这里的需求是要做学生的日程管理,也就是把学生的课程数据导出并生成一个日历,在日历对应的日期上添加课程日程。那么我们看看拿到的数据是什么样子的呢。
1 2 3 4 5 6
| @property (nonatomic, copy) NSString *courseid; @property (nonatomic, copy) NSString *courseName; @property (nonatomic, copy) NSString *year; @property (nonatomic, copy) NSString *semester; @property (nonatomic, copy) NSString *classroom; @property (nonatomic, copy) NSString *courseTimes;
|
这是由JSON直转的Model,这样的一些属性构成了一门课程,所有的属性都是字符串,那么也就是说每个Model对象是一个课程,每个课程的上课时间属性包含了一个长字符串,包含了一周内该门课程所有的上课时间,举个例子,courseTimes = @"周三第5,6节{第1-16周|单周};周三第7节{第8-12周};周五第9,10节{第8-12周}"
,我们就要将这样的字符串上的信息,用Calendar的形式展现给用户。
所以很明确了,切字符串。
分析
我们要从这个字符串中获得什么样的信息呢?首先,要让课程显示在正确的日期中,那么我们要提取出星期几、第几周,并且要标注是单周、双周还是哪一周有课,然后要提取出该课的上课具体节次。
所以,我针对时间,封装了Model,如下。
1 2 3 4 5 6 7
| @property (nonatomic, strong) NSNumber *weekday; @property (nonatomic, strong) NSArray<NSNumber *> *sequence; @property (nonatomic, strong) NSNumber *startWeek; @property (nonatomic, strong) NSNumber *endWeek; @property BOOL oddWeek; @property BOOL evenWeek;
|
对于星期几,我们可以做出一个数组,从一到七,匹配对应的文字,返回数组下标。开始周结束周、第几节课都转成数字处理,单双周由布尔值标记。每个Model对象代表一次课的上课时间。
Do it
由于分号;
在整个字符串中是唯一的,那么我们可以先用分号;
作为分割符,将这个字符串分割称为几个子串:
1 2 3 4
| NSArray *timeSubstrings = [course.courseTimes componentsSeparatedByString:@";"]; for (NSString *timeSubstring in timeSubstrings) { }
|
对于切割出的每一个子串,都是一次上课时间,那么我们可以在每次循环中,alloc
出一个时间Model对象。
1
| CourseTime *courseTime = [[CourseTime alloc] init];
|
接下来为了便于操作,我们可以用同样的方法把字符串从『节』的位置切割成两个子串。
然后换个新花样,用正则表达式,匹配出周几,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| NSArray *chineseWeekdays = @[@"一", @"二", @"三", @"四", @"五", @"六", @"日"]; NSRegularExpression *weekdayRegEx = [NSRegularExpression regularExpressionWithPattern:@"周.第" options:NSRegularExpressionCaseInsensitive error:&error]; if (!error) { NSTextCheckingResult *weekResult = [weekdayRegEx firstMatchInString:jieSubstring[0] options:0 range:NSMakeRange(0, [jieSubstring[0] length])]; if (weekResult) { NSString *chineseWeekdayResult = [timeSubstring substringWithRange:NSMakeRange(weekResult.range.location+1, 1)]; for (int i=0; i<7; ++i) { if ([chineseWeekdays[i] isEqualToString:chineseWeekdayResult]) { courseTime.weekday = [NSNumber numberWithInt:i+1]; break; } } } }
|
在这段代码中,我们用到了正则表达式周.第
来匹配我们需要的第几周,再对返回的range做一些调整,即可直接获取到一二三四这个数字,再对我们之前准备的中文数字数组进行遍历匹配,匹配到的数组+1就是我们要的。
接下来我们寻找课程节次,节次都是两个数字,中间用……敲豆麻袋!节次很奇葩,居然有一个数字的情况,想想其实是经常有一门课上三节连课的情况,教务系统直接把第三节课做成了单独一次课的形式,所以我们这里要考虑可能是一节课,也可能是两节课的情况,代码如下:
1 2 3 4 5 6 7 8
| if ([jieSubstring[0] rangeOfString:@","].location != NSNotFound) { NSArray *lessonStrs = [jieSubstring[0] componentsSeparatedByString:@","]; NSString *firstLessonStr = [lessonStrs[0] substringFromIndex:3]; NSString *secondLessonStr = lessonStrs[1]; courseTime.sequence = @[[NSNumber numberWithInteger:firstLessonStr.integerValue], [NSNumber numberWithInteger:secondLessonStr.integerValue]]; } else { courseTime.sequence = @[[NSNumber numberWithInteger:[jieSubstring[0] substringFromIndex:3].integerValue]]; }
|
这段代码第一行先去找两个数字之间的那个逗号,
如果能够找到,那么在这里切割一下,切割后的前子串的最后一个……敲豆麻袋,如果是第十节课第十一节课呢,两位数字,所以我们用substringFromIndex:
方法取后几个字符,这样一定可以取到所有数字;如果没有找到两个数字之间的逗号,说明我们不需要再切割,这里只有一节课,直接取字符即可。
之后就是单双周分割的问题了,利用刚刚的思路,我们可以通过寻找『|』字符来判定是否有单双周标记,然后取出单/双字判定,对Model里响应的布尔量做修改即可。还有周数,我们找到『-』,再取出其前后字符即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| if ([jieSubstring[1] rangeOfString:@"|"].location != NSNotFound) { NSArray *parityStrs = [jieSubstring[1] componentsSeparatedByString:@"|"]; if ([[parityStrs[1] substringWithRange:NSMakeRange(0, 1)] isEqualToString:@"单"]) { courseTime.oddWeek = YES; courseTime.evenWeek = NO; } else { courseTime.oddWeek = NO; courseTime.evenWeek = YES; } NSArray *dashStrs = [jieSubstring[1] componentsSeparatedByString:@"-"]; courseTime.startWeek = [NSNumber numberWithInteger:[dashStrs[0] substringFromIndex:2].integerValue]; courseTime.endWeek = [NSNumber numberWithInteger:[dashStrs[1] substringWithRange:NSMakeRange(0, [dashStrs[1] length]-1)].integerValue]; } else { courseTime.oddWeek = YES; courseTime.evenWeek = YES; NSArray *dashStrs = [jieSubstring[1] componentsSeparatedByString:@"-"]; courseTime.startWeek = [NSNumber numberWithInteger:[dashStrs[0] substringFromIndex:2].integerValue]; courseTime.endWeek = [NSNumber numberWithInteger:[dashStrs[1] substringWithRange:NSMakeRange(0, [dashStrs[1] length]-2)].integerValue]; }
|