歌词处理-时间、歌词截取 - (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 

@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 *)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 *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

你可能感兴趣的:(歌词处理-时间、歌词截取 - (Obj-C))