iOS 簡單分割小說章節(jié)

基本的思路:

  1. 用正則獲取章節(jié)名稱所在的位置(NSRange)
  2. 結合下一章的章節(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

此外還需要解決的問題:

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

參考內容
iOS txt小說斷章正則表達式實現
TXT小說斷章實現

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,697評論 19 139
  • 本文筆記源自這里——[實驗樓]歡迎大家在下面交流其中有問題的地方喜歡請點收藏,每日更新(全部已親自實踐). 一. ...
    東皇Amrzs閱讀 4,334評論 7 54
  • 7月1日開始,進行社群的腦洞大開訓練運營。 我當時所具備的條件:①較為豐富的經驗②更多的時間③更強的耐心 報名通知...
    博雅大師兄閱讀 590評論 0 3
  • 數十日不見樓下阿婆,突然有種不詳預感。一日上下樓時隱約間聽到聊天對話,幾天后才得知,阿婆摔倒已經住院一個多月了,有...
    令令噠閱讀 226評論 0 0

友情鏈接更多精彩內容