歌词处理-时间、歌词截取 - (Obj-C)

歌词.lrc文件实际存放的就是二进制的字符串
歌词.lrc文件的解析实际就是二进制字符串解析

内部格式大致为:

[03:02.00][01:05.00]这晚夜没有吻别

主要由两部分组成: 时间部分歌词部分
两个时间戳代表同一句歌词会在两个时间下显示

歌词解析:

1.先抽取一个歌词模型类(存放每一句歌词)
2.声明属性:时间(每句的起始时间) 和 歌词(每一句)
3.创建一个工具类,专门用作解析歌词,供外界直接调用

3.1 读取歌词字符串
3.2 分隔字符串为一个存放每一句歌词的数组(包含时间和歌词)
3.3 遍历存放歌词的数组,根据时间格式使用正则表达式过滤字符串,得到一个存放NSTextCheckingResult对象的数组
3.4 截取时间和歌词,遍历存放歌词(含时间和歌词)的数组:
      3.4.1 遍历存放NSTextCheckingResult对象的数组,通过range属性获得时间(因为每句歌词可能含多个时间戳)
      3.4.2 通过range属性,截取歌词
3.5 给歌词模型属性赋值
3.6 将得到的歌词模型对象添加到可变数组
3.7 将存放歌词模型对象的数组重新排序
  • 时间截取:
1. 每句歌词可能含多个时间戳,所以在遍历歌词数组时,使用正则表达式过滤歌词,会得到一个存放NSTextCheckingResult对象的数组,这里需要使用到NSTextCheckingResult的range属性,再次遍历存放NSTextCheckingResult对象的数组,通过range属性截取时间字符串
2. 截取的是时间字符串,为了便于使用,这里将字符串转为NSTimeInterval格式再进行存储(歌词模型中也是直接使用NSTimeInterval声明的)
  • 歌词截取:
参考_歌词内部格式示例_,一句歌词可能会有多个时间戳,根据正则表达式获取到存放时间的数组,取出数组中最后一个元素,也就是每句歌词中最后的一个时间戳:
用最后的时间戳的local + length才是全部时间部分的长度,也就得到了后面歌词的索引
  • 示例代码:

歌词模型类(只是声明了属性,并未提供方法):

#import <Foundation/Foundation.h>

@interface JSLyricModel : NSObject

// 该句歌词的初始时间
@property (nonatomic,assign) NSTimeInterval initialTime;
// 该句歌词
@property (nonatomic,copy) NSString *content;


@end

歌词解析工具类:

#import "JSLyricManager.h"
#import "NSDateFormatter+Shared.h"
#import "JSLyricModel.h"

@implementation JSLyricManager

+ (NSArray<JSLyricModel *> *)parserLyricWithFileName:(NSString *)fileName{
    
    // 取出歌词字符串
    NSString *filePath = [[NSBundle mainBundle]pathForResource:fileName ofType:nil];
    NSString *lyricStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    
    // 分隔字符串
    NSArray *lyricArr = [lyricStr componentsSeparatedByString:@"\n"];
    
    
    /*      正则表达式过滤字符串:
     [00:19.00]曲:河合奈保子 词:向雪怀
     [02:19.00][00:23.00]仍然倚在失眠夜望天边星宿
     */
    NSString *regularExpressionString = @"\\[[0-9]{2}:[0-9]{2}.[0-9]{2}\\]";
    NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regularExpressionString options:0 error:nil];
    
    // 存放歌词对象的临时可变数组
    NSMutableArray *tempMarr = [NSMutableArray array];
    
    //遍历歌词数组,取出每一句歌词
    for (NSString *element in lyricArr) {
        
        // 正则表达式遍历
        NSArray<NSTextCheckingResult *> *textCheckingResult = [regularExpression matchesInString:element options:0 range:NSMakeRange(0, element.length)];
        
        // 2.截取歌词内容
        NSTextCheckingResult *lastTimeString = textCheckingResult.lastObject;// 取出得到数组中的最后一个时间元素,用来获取range
        
        // 截取歌词 (一句歌词可能会有多个时间戳,取到最后一个时间戳,用自己的local + length才是全部时间部分的长度,也就得到了后面歌词的索引)
        NSString *lyricContent = [element substringFromIndex:lastTimeString.range.length + lastTimeString.range.location];
        
        // 同一句歌词可能多处显示,所以返回值是一个数组,遍历取出每一个起始时间字符串
        for (NSTextCheckingResult *result in textCheckingResult) {

            // 1. 截取时间字符串
            NSString *lyricSubString = [element substringWithRange:NSMakeRange(result.range.location, result.range.length)];
            
            // 截取玩后设置每一句歌词的起始时间
            NSTimeInterval currentLyricInitialTime = [self timeIntervalWithTimeString:lyricSubString];
            
            // 创建歌词模型
            JSLyricModel *model = [[JSLyricModel alloc]init];
            // 模型赋值
            model.initialTime = currentLyricInitialTime;// 给歌词模型的歌词初试时间赋值
            model.content = lyricContent;               // 给歌词模型的歌词内容赋值
            
            // 添加到临时可变数组
            [tempMarr addObject:model];
            
        }
        
    }
    
    // 歌词起始时间排序
    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"initialTime" ascending:YES];
    NSArray *lyricModelArr = [tempMarr sortedArrayUsingDescriptors:@[descriptor]];
    
    
    // 进行解析
    return lyricModelArr;
}

// 将时间字符串转换为NSTimerInterval类型,方便外面直接判断
+ (NSTimeInterval)timeIntervalWithTimeString:(NSString *)timeString{
    
    // 时间字符串 --> 日期对象 NSDate  --> 计算对应的时间间隔
    NSDateFormatter *dateFormatter = [NSDateFormatter sharedManager];
    // 设置格式
    dateFormatter.dateFormat = @"[mm:ss.SS]";
    // 创建初始时间对象 用来计算时间间隔
    NSDate *initialDate = [dateFormatter dateFromString:@"[00:00.00]"];
    // 将字符串转换为NSDate
    NSDate *targetDate = [dateFormatter dateFromString:timeString];
    
    // 计算时间间隔
    return [targetDate timeIntervalSinceDate:initialDate];
    
}


@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • 前言 要解析 lrc 格式的歌词, 首先需要知道什么是 lrc 歌词, 还需要知道 lrc 歌词的规范. 在这里先...
    李国安阅读 5,374评论 8 14
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,221评论 11 349
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • Sorry Sorry 锁骨旁边 蓝色英文纹身 戴着口罩的你 高冷的让我窒息 然而你的眼神 那么迷人 我只敢用余光...
    停停不能停阅读 184评论 0 2