歌詞.lrc文件實際存放的就是二進(jìn)制的字符串
歌詞.lrc文件的解析實際就是二進(jìn)制字符串解析
內(nèi)部格式大致為:
[03:02.00][01:05.00]這晚夜沒有吻別
主要由兩部分組成: 時間部分 和 歌詞部分
兩個時間戳代表同一句歌詞會在兩個時間下顯示
歌詞解析:
1.先抽取一個歌詞模型類(存放每一句歌詞)
2.聲明屬性:時間(每句的起始時間) 和 歌詞(每一句)
3.創(chuàng)建一個工具類,專門用作解析歌詞,供外界直接調(diào)用
3.1 讀取歌詞字符串
3.2 分隔字符串為一個存放每一句歌詞的數(shù)組(包含時間和歌詞)
3.3 遍歷存放歌詞的數(shù)組,根據(jù)時間格式使用正則表達(dá)式過濾字符串,得到一個存放NSTextCheckingResult對象的數(shù)組
3.4 截取時間和歌詞,遍歷存放歌詞(含時間和歌詞)的數(shù)組:
3.4.1 遍歷存放NSTextCheckingResult對象的數(shù)組,通過range屬性獲得時間(因為每句歌詞可能含多個時間戳)
3.4.2 通過range屬性,截取歌詞
3.5 給歌詞模型屬性賦值
3.6 將得到的歌詞模型對象添加到可變數(shù)組
3.7 將存放歌詞模型對象的數(shù)組重新排序
- 時間截取:
1. 每句歌詞可能含多個時間戳,所以在遍歷歌詞數(shù)組時,使用正則表達(dá)式過濾歌詞,會得到一個存放NSTextCheckingResult對象的數(shù)組,這里需要使用到NSTextCheckingResult的range屬性,再次遍歷存放NSTextCheckingResult對象的數(shù)組,通過range屬性截取時間字符串
2. 截取的是時間字符串,為了便于使用,這里將字符串轉(zhuǎn)為NSTimeInterval格式再進(jìn)行存儲(歌詞模型中也是直接使用NSTimeInterval聲明的)
- 歌詞截取:
參考_歌詞內(nèi)部格式示例_,一句歌詞可能會有多個時間戳,根據(jù)正則表達(dá)式獲取到存放時間的數(shù)組,取出數(shù)組中最后一個元素,也就是每句歌詞中最后的一個時間戳:
用最后的時間戳的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"];
/* 正則表達(dá)式過濾字符串:
[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];
// 存放歌詞對象的臨時可變數(shù)組
NSMutableArray *tempMarr = [NSMutableArray array];
//遍歷歌詞數(shù)組,取出每一句歌詞
for (NSString *element in lyricArr) {
// 正則表達(dá)式遍歷
NSArray<NSTextCheckingResult *> *textCheckingResult = [regularExpression matchesInString:element options:0 range:NSMakeRange(0, element.length)];
// 2.截取歌詞內(nèi)容
NSTextCheckingResult *lastTimeString = textCheckingResult.lastObject;// 取出得到數(shù)組中的最后一個時間元素,用來獲取range
// 截取歌詞 (一句歌詞可能會有多個時間戳,取到最后一個時間戳,用自己的local + length才是全部時間部分的長度,也就得到了后面歌詞的索引)
NSString *lyricContent = [element substringFromIndex:lastTimeString.range.length + lastTimeString.range.location];
// 同一句歌詞可能多處顯示,所以返回值是一個數(shù)組,遍歷取出每一個起始時間字符串
for (NSTextCheckingResult *result in textCheckingResult) {
// 1. 截取時間字符串
NSString *lyricSubString = [element substringWithRange:NSMakeRange(result.range.location, result.range.length)];
// 截取玩后設(shè)置每一句歌詞的起始時間
NSTimeInterval currentLyricInitialTime = [self timeIntervalWithTimeString:lyricSubString];
// 創(chuàng)建歌詞模型
JSLyricModel *model = [[JSLyricModel alloc]init];
// 模型賦值
model.initialTime = currentLyricInitialTime;// 給歌詞模型的歌詞初試時間賦值
model.content = lyricContent; // 給歌詞模型的歌詞內(nèi)容賦值
// 添加到臨時可變數(shù)組
[tempMarr addObject:model];
}
}
// 歌詞起始時間排序
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"initialTime" ascending:YES];
NSArray *lyricModelArr = [tempMarr sortedArrayUsingDescriptors:@[descriptor]];
// 進(jìn)行解析
return lyricModelArr;
}
// 將時間字符串轉(zhuǎn)換為NSTimerInterval類型,方便外面直接判斷
+ (NSTimeInterval)timeIntervalWithTimeString:(NSString *)timeString{
// 時間字符串 --> 日期對象 NSDate --> 計算對應(yīng)的時間間隔
NSDateFormatter *dateFormatter = [NSDateFormatter sharedManager];
// 設(shè)置格式
dateFormatter.dateFormat = @"[mm:ss.SS]";
// 創(chuàng)建初始時間對象 用來計算時間間隔
NSDate *initialDate = [dateFormatter dateFromString:@"[00:00.00]"];
// 將字符串轉(zhuǎn)換為NSDate
NSDate *targetDate = [dateFormatter dateFromString:timeString];
// 計算時間間隔
return [targetDate timeIntervalSinceDate:initialDate];
}
@end