基本的思路:
- 用正則獲取章節(jié)名稱所在的位置(
NSRange) - 結合下一章的章節(jié)名的位置拿到本章內容信息
具體實現方法
/**
提取章節(jié)的NSRange信息
@param content 文本內容
@return `range字符串`數組
*/
+ (NSArray<NSTextCheckingResult *> *)extractChapterListWithContent:(NSString *)content{
NSString* regPattern = @"(\\s)+[第]{0,1}[0-9一二三四五六七八九十百千萬]+[章回節(jié)卷集幕計][ \t]*(\\S)*";
NSError* error = NULL;
NSRegularExpression* regExp = [NSRegularExpression regularExpressionWithPattern:regPattern
options:NSRegularExpressionCaseInsensitive
error:&error];
return [regExp matchesInString:content options:NSMatchingReportCompletion range:NSMakeRange(0, content.length)];
}
根據 title Range 提取章節(jié)所需信息
/**
根據 title Range 提取章節(jié)所需信息
@param content 字符串內容
@param maintainEmptyCharcter 是否保留空章節(jié)
@return ChapterModel數組
*/
+ (NSArray<ChapterModel *> *)analyseTxtWithContent:(NSString *)content
maintainEmptyCharcter:(BOOL)maintainEmptyCharcter{
NSArray<NSTextCheckingResult *> *matchResult = [self extractChapterListWithContent:content];
NSMutableArray *chapterModels = @[].mutableCopy ;
if (matchResult.count == 0) {
ChapterModel *model = [ChapterModel new] ;
model.title = @"內容";
model.contentRange = NSMakeRange(0, content.length);
model.allContentRange = NSMakeRange(0, content.length);
return @[model];
}
for (NSInteger i = 0; i < matchResult.count ; i++) {
NSRange titleRange = matchResult[i].range;
NSString *chapterTitle = [[content yj_substringWithRange:titleRange] trimmed];
NVLog(@"%@",chapterTitle);
if (i == 0) { //第0章前
NSString *firstTitle = @"開始";
NSString *contentString = [content yj_substringWithRange:NSMakeRange(0, titleRange.location)];
if (contentString.trimmed.length > 0 ) {
ChapterModel *model2 = [ChapterModel modelWithTitle:firstTitle
titleRange:NSMakeRange(0, 0)
allContentRange:NSMakeRange(0, titleRange.location)];
[chapterModels addObject:model2];
}
}
if (i < matchResult.count-1) {
NSRange nextRange = matchResult[i+1].range;
if (nextRange.location > titleRange.location) {
NSInteger length = nextRange.location - titleRange.location ;
ChapterModel *model2 = [ChapterModel modelWithTitle:chapterTitle
titleRange:titleRange
allContentRange:NSMakeRange(titleRange.location, length)];
[self chapterModels:chapterModels addModel:model2 content:content maintainEmpty:maintainEmptyCharcter];
}
}
if (i == matchResult.count-1){ //最后章節(jié)
ChapterModel *model2 = [ChapterModel modelWithTitle:chapterTitle
titleRange:titleRange
allContentRange:NSMakeRange(titleRange.location,content.length - titleRange.location)];
[self chapterModels:chapterModels addModel:model2 content:content maintainEmpty:maintainEmptyCharcter];
}
}
return [chapterModels copy];
}
+ (void)chapterModels:(NSMutableArray *)chapterModels
addModel:(ChapterModel *)model
content:(NSString *)content
maintainEmpty:(BOOL)maintainEmptyCharcter{
NSInteger contentLength = [[content yj_substringWithRange:model.contentRange] trimmed].length;
//保留空章節(jié) 或者 章節(jié)有內容
if (maintainEmptyCharcter == YES || contentLength > 0) {
[chapterModels addObject:model];
}
}
添加輔助方法
新增ChapterModel類:
@interface ChapterModel : NSObject
//章節(jié)標題
@property(nonatomic,copy)NSString *title ;
@property(nonatomic)NSRange titleRange ;
//章節(jié)內容
@property(nonatomic)NSRange contentRange ;
//內容(包括title)
@property(nonatomic)NSRange allContentRange;
@end
@implementation ChapterModel
+ (instancetype)modelWithTitle:(NSString *)title
titleRange:(NSRange )titleRange
allContentRange:(NSRange )allContentRange
{
ChapterModel *model = [[ChapterModel alloc]init];
model.title = title ;
model.titleRange = titleRange ;
model.allContentRange = allContentRange ;
model.contentRange = NSMakeRange(titleRange.location + titleRange.length,
allContentRange.length - titleRange.length);
return model;
}
@end
添加NSString類別,防止substringWithRange越界
@implementation NSString (YJSafe)
//防止越界
- (NSString *)yj_substringWithRange:(NSRange)range{
if (self.length >= range.location + range.length) {
return [self substringWithRange:range];
}
return @"";
}
- (NSString *)trimmed{
NSCharacterSet* whiteSpaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
return [self stringByTrimmingCharactersInSet:whiteSpaceSet];
}
@end
異步獲取
/**
提取章節(jié)信息
@param content 文本內容
@param isAsync 是否是異步
@param isNeedMaintainEmptyCharcter 是否需要提取空的章節(jié)
@param result 返回ChapterModel數組
*/
+ (void)extractNovelWithContent:(NSString *)content
async:(BOOL)isAsync
maintainEmptyCharcter:(BOOL)isNeedMaintainEmptyCharcter
result:(void(^)(NSArray<ChapterModel *> *models))result {
if (result == nil) { return ;}
if (isAsync) {
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSArray *models = [self analyseTxtWithContent:content maintainEmptyCharcter:isNeedMaintainEmptyCharcter];
dispatch_async(dispatch_get_main_queue(), ^{
result(models);
});
});
}else {
result([self analyseTxtWithContent:content maintainEmptyCharcter:isNeedMaintainEmptyCharcter]);
}
}
預覽:
方法調用

2017011818316novel_code.png
效果預覽

2017011872898nove_show.png
此外還需要解決的問題:
- 這個正則是根據這篇文章修改的,還不能匹配
第n章和章節(jié)名字多個空格的情況 - 有的標題可能比較特別 ,好比
【《》目錄 第二回 悟徹菩提真妙理 斷魔歸本合元神】。 這樣匹配“第二回”所在的一行應該比較好
- 不過還有這樣的
【《》目錄 第十一回 還受生唐王遵善果 度孤魂蕭【《》目錄 第十二回 玄奘秉誠建大會 觀音顯象化金蟬 】,章節(jié)內容直接缺失。 如果匹配所在行估計會出問題。 - 忽然覺得自己該惡補下正則的知識了。。。。