基本的思路:
- 用正則獲取章節(jié)名稱所在的位置(
NSRange) - 結(jié)合下一章的章節(jié)名的位置拿到本章內(nèi)容信息
具體實(shí)現(xiàn)方法
/**
提取章節(jié)的NSRange信息
@param content 文本內(nèi)容
@return `range字符串`數(shù)組
*/
+ (NSArray<NSTextCheckingResult *> *)extractChapterListWithContent:(NSString *)content{
NSString* regPattern = @"(\\s)+[第]{0,1}[0-9一二三四五六七八九十百千萬(wàn)]+[章回節(jié)卷集幕計(jì)][ \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)];
}
根據(jù) title Range 提取章節(jié)所需信息
/**
根據(jù) title Range 提取章節(jié)所需信息
@param content 字符串內(nèi)容
@param maintainEmptyCharcter 是否保留空章節(jié)
@return ChapterModel數(shù)組
*/
+ (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 = @"內(nèi)容";
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 = @"開(kāi)始";
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é)有內(nèi)容
if (maintainEmptyCharcter == YES || contentLength > 0) {
[chapterModels addObject:model];
}
}
添加輔助方法
新增ChapterModel類:
@interface ChapterModel : NSObject
//章節(jié)標(biāo)題
@property(nonatomic,copy)NSString *title ;
@property(nonatomic)NSRange titleRange ;
//章節(jié)內(nèi)容
@property(nonatomic)NSRange contentRange ;
//內(nèi)容(包括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 文本內(nèi)容
@param isAsync 是否是異步
@param isNeedMaintainEmptyCharcter 是否需要提取空的章節(jié)
@param result 返回ChapterModel數(shù)組
*/
+ (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]);
}
}
預(yù)覽:
方法調(diào)用

2017011818316novel_code.png
效果預(yù)覽

2017011872898nove_show.png
此外還需要解決的問(wèn)題:
- 這個(gè)正則是根據(jù)這篇文章修改的,還不能匹配
第n章和章節(jié)名字多個(gè)空格的情況 - 有的標(biāo)題可能比較特別 ,好比
【《》目錄 第二回 悟徹菩提真妙理 斷魔歸本合元神】。 這樣匹配“第二回”所在的一行應(yīng)該比較好
- 不過(guò)還有這樣的
【《》目錄 第十一回 還受生唐王遵善果 度孤魂蕭【《》目錄 第十二回 玄奘秉誠(chéng)建大會(huì) 觀音顯象化金蟬 】,章節(jié)內(nèi)容直接缺失。 如果匹配所在行估計(jì)會(huì)出問(wèn)題。 - 忽然覺(jué)得自己該惡補(bǔ)下正則的知識(shí)了。。。。
參考內(nèi)容
iOS txt小說(shuō)斷章正則表達(dá)式實(shí)現(xiàn)
TXT小說(shuō)斷章實(shí)現(xiàn)