歌词处理-时间、歌词截取 - (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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

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