我觉得要想解析lrc 首先大家应该了解一下lrc文件的结构,大家可以去看一下**百科 我这里粗略的写一下;

■ 时间标签(Time-tag)
形式为"[mm:ss]"(分钟数:秒数)
或"[mm:ss.ff]"。数字须为非负整数 
■ 标识标签(ID-tags)
其格式为"[标识名:值]"。大小写等价。以下是预定义的标签。
[ar:艺人名]
[ti:曲名]
[al:专辑名]
[by:编者(指编辑LRC歌词的人)]
[offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
[t_time:(总时长)]
每一句歌词可能有多个播放时间,如:
[00:12:34][00:34:15][00:25:54]测试
所以解析的时候都要考虑到;
下面附源码,源码中有关键点的注释;源码下面还会有解释
注:代码中很多部分采用了三元式,希望大家可以看懂,三元式可以和if else 语句替换,大家自己可以网上搜一下,后面知识点会稍微说一下,不会很详细  
 
 
 //
// LyricsAnalysis.h
// 08-10-MusicPlayer
//
// Created by Ibokan on 15/8/21.
// Copyright (c) 2015年 Crazy凡. All rights reserved.
// #import <Foundation/Foundation.h> @interface LyricsAnalysis : NSObject
@property (nonatomic,strong)NSString *ar;//演唱
@property (nonatomic,strong)NSString *ti;//歌曲名
@property (nonatomic,strong)NSString *al;//专辑名
@property (nonatomic,strong)NSString *by;//歌词作者
@property (nonatomic,strong)NSString *t_time;//歌曲总时长
@property (nonatomic,strong)NSMutableArray *lrcArrayTime;//时间数组
@property (nonatomic,strong)NSMutableArray *lrcArrayStr;//歌词数组 - (instancetype)init;
- (instancetype)initWithFileName:(NSString *)name ofType:(NSString *)type;
- (instancetype)initWithFilePath:(NSString *)filePath;
- (void)lyricsAnalysisWithFileName:(NSString *)name ofType:(NSString *)type;
- (void)lyricsAnalysisWithFilePath:(NSString *)filePath;
@end

以上是.h头文件源码

以下是.m源文件源码

 //
// LyricsAnalysis.m
// 08-10-MusicPlayer
//
// Created by Ibokan on 15/8/21.
// Copyright (c) 2015年 Crazy凡. All rights reserved.
// #import "LyricsAnalysis.h" @interface LyricsAnalysis ()
@property double offset;//歌词时间调整变量
@end
@implementation LyricsAnalysis //初始化
- (instancetype)init
{
self = [super init];
if (self) {
self.ar = [[NSString alloc]init];
self.ti = [[NSString alloc]init];
self.by = [[NSString alloc]init];
self.al = [[NSString alloc]init];
self.offset = ;
self.t_time = [[NSString alloc]init];//歌曲总时长单位(s)
self.lrcArrayStr = [[NSMutableArray alloc]init];//歌词数组初始化
self.lrcArrayTime = [[NSMutableArray alloc]init];//时间数组初始化
}
return self;
}
//带文件名的初始化
- (instancetype)initWithFileName:(NSString *)name ofType:(NSString *)type
{
self = [self init];
[self lyricsAnalysisWithFileName:name ofType:type];
return self;
}
//带文件路径的初始化
- (instancetype)initWithFilePath:(NSString *)filePath
{
self = [self init];
[self lyricsAnalysisWithFilePath:filePath];
return self;
}
//处理文件名歌词
- (void)lyricsAnalysisWithFileName:(NSString *)name ofType:(NSString *)type
{
[self lyricsAnalysisWithFilePath:[[NSBundle mainBundle] pathForResource:name ofType:type]];//构建filepath
}
//处理文件路径
- (void)lyricsAnalysisWithFilePath:(NSString *)filePath
{
NSString *strlrc = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSMutableArray * arraylrc = [[NSMutableArray alloc] initWithArray:[strlrc componentsSeparatedByString:@"\n"]];
NSArray *StrToInt = [NSArray arrayWithObjects:@"ar",@"ti",@"al",@"by",@"of",@"t_",nil];//NSString switch 配置
BOOL flag = YES;
while(flag)
{
NSString *temp = arraylrc[];
switch ((int)[StrToInt indexOfObject:[temp substringWithRange:NSMakeRange(, )]])
{
case :self.ar = [[temp substringFromIndex:]stringByReplacingOccurrencesOfString:@"]" withString:@"\0"];break;
case :self.ti = [[temp substringFromIndex:]stringByReplacingOccurrencesOfString:@"]" withString:@"\0"];break;
case :self.al = [[temp substringFromIndex:]stringByReplacingOccurrencesOfString:@"]" withString:@"\0"];break;
case :self.by = [[temp substringFromIndex:]stringByReplacingOccurrencesOfString:@"]" withString:@"\0"];break;
case :self.offset = [[[temp substringFromIndex:] stringByReplacingOccurrencesOfString:@"]" withString:@"\0"] doubleValue];break;
case :self.t_time = [[temp substringFromIndex:] stringByReplacingOccurrencesOfString:@")]" withString:@"\0"];break;
default:flag = NO; break;
}
flag?[arraylrc removeObjectAtIndex:]:nil;//判断是否需要移除已经被读取的信息(是歌词则不移除)
}// lrc时间的格式分3种:[mm:ss.SS]、[mm:ss:SS]、[mm:ss];第一种是标准形式,后面两种存在但是不标准;先把时间字符串按照“:”拆分,生成{mm ss.SS}、{mm ss SS}、{mm ss};对于1、3,直接取doubleValue即可;注意分钟*60;对于第二种情况需要单独处理SS(毫秒)位;
for (NSString *str in arraylrc) {
NSArray * ArrayTemp = [str componentsSeparatedByString:@"]"];//分割每一句歌词
for(int j = ; j < ArrayTemp.count - ;j++)
{
NSArray * Arraytime = [[ArrayTemp[j] substringFromIndex:] componentsSeparatedByString:@":"];//分割时间字符串
double timedouble = [Arraytime[] doubleValue]*60.0 + [Arraytime[] doubleValue];//处理分钟和秒
timedouble += Arraytime.count > ? [[[NSString alloc]initWithFormat:@"0.%@",Arraytime[]] doubleValue]:;//处理毫秒位
timedouble += (self.offset / 1000.0);//时间调整
timedouble = timedouble > ? timedouble : ;//避免因为时间调整导致的时间<0
int i = ;
while (i < self.lrcArrayTime.count && [self.lrcArrayTime[i++] doubleValue] < timedouble);//查找当前歌词的插入位置
[self.lrcArrayTime insertObject:[[NSString alloc]initWithFormat:@"%lf",timedouble] atIndex:i];//插入时间数组
[self.lrcArrayStr insertObject:ArrayTemp[ArrayTemp.count-] atIndex:i];//插入歌词数组
}
}
}
@end

知识点:

1、[[NSBundle mainBundle] pathForResource:name ofType:type]]

//路径构建,传进的name 和 type 参数需要做 路径构建

2、NSArray *StrToInt = [NSArray arrayWithObjects:@"ar",@"ti",@"al",@"by",@"of",@"t_",nil];//NSString  switch 配置

switch ((int)[StrToInt indexOfObject:[temp substringWithRange:NSMakeRange(1, 2)]])

//OC的switch  case 不支持NSString  这可能让很多学过Java的小伙伴很*疼,利用NSArray indexOfObject:方法实现NSString 映射到数字(数组下标),以便于调用 switch case;
3、

substringFromIndex//截取

stringByReplacingOccurrencesOfString:@"]" withString:@"\0"//替换

NSMutableArray * arraylrc = [[NSMutableArray alloc] initWithArray:[strlrc componentsSeparatedByString:@"\n"]];//分割

大量的字符串  处理函数  大家自多看吧,毕竟很常用也很重要

4、三元式的读取

条件?a:b; 满足条件返回a  不满足条件返回b  如果a b  是表达式  则会自动执行表达式

新增部分:

代码的第58行,替换成:BOOL flag = arraylrc.count > 0 ? YES : NO;  //防止错误路径或者歌词文件为空导致的概率性崩溃;

代码的第89行,插入:self.lrcArrayTime.count == 0 ? [self.lrcArrayTime insertObject:@"0" atIndex:0],[self.lrcArrayStr insertObject:@"未找到歌词!" atIndex:0]:nil;  //又是一个三元式,没办法喜欢他, 和上面作用一样,不一样的是插入了一句提示语,找不到歌词。

此处编辑于:15-09-23 12时

注意:以上部分未在下面的源文件中更新

代码中的细节,基本都做了注释,不懂得可以留言,我会尽可能的答复;

 

ios开发学习--歌词处理--解析lrc文件的更多相关文章

  1. Android开发学习---使用XmlPullParser解析xml文件

    Android中解析XML的方式主要有三种:sax,dom和pull关于其内容可参考:http://blog.csdn.net/liuhe688/article/details/6415593 本文将 ...

  2. ios开发 学习积累20161027~20161031

    前言 学习ios这几天来,总结下,函数的定义,调用.跟其他语言都有一定的区别: 几个特别重要的就是对象的迭代的使用和判断.取随机数.动画的实现及数组的深入研究等等 之前的总结地址 ios开发 学习积累 ...

  3. iOS开发中的Html解析方法

    iOS开发中的Html解析方法 本文作者为大家介绍了在iOS开发中的Html解析方法,并同时提供了Demo代码的下载链接,Demo 解析了某个网站(具体可在代码中查看)的html网页,提取了图片以及标 ...

  4. iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (以后谁不会了,直接将连接给他)

    iOS 开发中,关于xxx.xcodeproj 文件冲突的解决方案 (一有冲突要手把手教一遍,太麻烦了,现在总结下,以后谁不会了,连接直接发他). 关于xxx.xcodeproj 文件冲突的话,是比较 ...

  5. iOS开发之网络数据解析(二)--XML解析简介

    前言:本篇随笔介绍的是XML解析. 正文: 1.XML解析方式有2两种: DOM:一次性将整个XML数据加载进内存进行解析,比较适合解析小文件 SAX:从根元素开始,按顺序一个元素一个元素往下解析,比 ...

  6. iOS开发系列--UITableView全面解析

    --UIKit之UITableView 概述 在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似于微信.QQ.新浪微博等软件基本上随处都是U ...

  7. iOS开发学习笔记:基础篇

    iOS开发需要一台Mac电脑.Xcode以及iOS SDK.因为苹果设备都具有自己封闭的环境,所以iOS程序的开发必须在Mac设备上完成(当然,黑苹果应该也是可以的,但就需要花很多的精力去折腾基础环境 ...

  8. iOS开发学习 阶段过程简述

    下面就简单介绍一下我iOS开发的感受,也是学习iOS开发的一个体系架构. 1 iOS开发环境 1.1 开发环境 标准的配置是Mac OS X + Xcode. MacOSX的话首选用苹果电脑,macm ...

  9. iOS开发学习概述及知识整理

    设计师设计出来了一个不错的引导界面,然而当我看到设计稿的时候,我们的app也没几天就要上线了.这个界面模仿了Evernote iOS app的风格. 我以迅雷不及掩耳盗铃之势开始在Xcode上编程,用 ...

随机推荐

  1. [置顶] iptables 性能 测试

    一直研究iptables 性能,这几天刚好有硬件资源,于是发始下手测试iptables NAT 性…… 硬件环境  : 服务器: IBM x3650 ( 4G  E5645 6核 12线程) ESXi ...

  2. 利用Java API通过路径过滤上传多文件至HDFS

    在本地文件上传至HDFS过程中,很多情况下一个目录包含很多个文件,而我们需要对这些文件进行筛选,选出符合我们要求的文件,上传至HDFS.这时就需要我们用到文件模式. 在项目开始前,我们先掌握文件模式 ...

  3. 一次优化web项目的经历记录(二)

    一次优化web项目的经历记录 这段时间以来的总结与反思 前言:最近很长一段时间没有更新博客了,忙于一堆子项目的开发,严重拖慢了学习与思考的进程. 开水倒满了需要提早放下杯子,晚了就会烫手,这段时间以来 ...

  4. 使用PHP实现蜘蛛访问日志统计

    $useragent = addslashes(strtolower($_SERVER['HTTP_USER_AGENT'])); if (strpos($useragent, 'googlebot' ...

  5. JAva Collections类方法详解

    http://blog.csdn.net/lskyne/article/details/8961014 Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素 ...

  6. Android开发---支付宝功能接口(支付功能)(转载!)

    最近在做一个关于购物商城的项目,项目里面付款这块我选的是调用支付宝的接口,因为用的人比较多. 在网上搜索了以下,有很多这方面的教程,但大部分教程过于陈旧,而且描述的过于简单.而且支付宝提供的接口一直在 ...

  7. TFS扩展开发中遇到的坑

    本码农最近开发一个VS扩展,其中有些功能涉及到文件的签出.我们公司用的是TFS,遇到了一些奇特的现象,将解决过程记录如下. 一.明明在线的连接却Offline属性等于True public stati ...

  8. Dictionary的遍历和修改

    /// <summary>        /// 初始化一个Dic        /// </summary>        public static void mainTe ...

  9. 用于显示上个月和下个月_PHP

    /** * 用于显示上个月和下个月 * @param int $sign 1:表示上个月 0:表示下个月 * @return string */ function GetMonth($sign=&qu ...

  10. [转]关于java中的 sychronized 同步方法 与 同步块的理解

    首先,需要说明一点,也是最重要的一点,无论是同步方法 还是 同步块 都是只针对同一个对象的多线程而言的,只有同一个对象产生的多线程,才会考虑到 同步方法 或者是 同步块,如果定义多个实例的同步,可以考 ...