java中用正则表达式解析LRC文件
2012-08-04 21:17
267 查看
跟着Mars老师
一起写android中的Mp3播放器
真是受益匪浅
再次感谢老师的无私奉献
不过其中问题也确实不少
感觉老师的代码重构做的不够
其中对LRC文件的解析也弄的比较马虎
今天特意花了一天的时间
好好研究了正则表达式
也仔细思索了LRC文件到底应该怎么来解析
以下先分析思路
再给出实现代码
首先
我们应该明白LRC文件的组成
LRC文件本质就是个符合一定格式规范的文本文件
这一点对照XML文件就很好理解了
一个LRC文件的组成
通常由以下几个部分组成
[ti:约定]-------标题
[ar:周惠]------演唱者
[al:周蕙-精选]-------专辑
[00:26.00]远处的钟声回荡在雨里--------每句内容由一个时间点和内容组成
同时应该注意到
[02:23.00][00:49.00]一路从泥泞走到了美景---------在每个内容可能出现多个时间点
然后
我们 用一个实体类
LrcInfo
来封装每个Lrc文件的具体内容
Java代码
package javamzd.mp3player.Info;
import java.util.HashMap;
/**
* 用来封装歌词信息的类
* @author Administrator
*
*/
public class LrcInfo {
private String title;//歌曲名
private String singer;//演唱者
private String album;//专辑
private HashMap<Long,String> infos;//保存歌词信息和时间点一一对应的Map
//以下为getter() setter()
}
3.读入Lrc文件,开始逐行解析
解析步骤:
1.读入文件
2.封装为BufferedReader对象
3.调用readline()方法逐行读取数据,得到String str
4.用parser()方法解析每一条具体的String语句
5.每句解析完后,将得到的内容在LrcInfo对象中进行设置
Java代码
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 此类用来解析LRC文件 将解析完整的LRC文件放入一个LrcInfo对象中 并且返回这个LrcInfo对象s author:java_mzd
*/
public class LrcParser {
private LrcInfo lrcinfo = new LrcInfo();
private long currentTime = 0;//存放临时时间
private String currentContent = null;//存放临时歌词
private Map<Long, String> maps = new HashMap<Long, String>();//用户保存所有的歌词和时间点信息间的映射关系的Map
/**
* 根据文件路径,读取文件,返回一个输入流
*
* @param path
* 路径
* @return 输入流
* @throws FileNotFoundException
*/
private InputStream readLrcFile(String path) throws FileNotFoundException {
File f = new File(path);
InputStream ins = new FileInputStream(f);
return ins;
}
public LrcInfo parser(String path) throws Exception {
InputStream in = readLrcFile(path);
lrcinfo = parser(in);
return lrcinfo;
}
/**
* 将输入流中的信息解析,返回一个LrcInfo对象
*
* @param inputStream
* 输入流
* @return 解析好的LrcInfo对象
* @throws IOException
*/
public LrcInfo parser(InputStream inputStream) throws IOException {
// 三层包装
InputStreamReader inr = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inr);
// 一行一行的读,每读一行,解析一行
String line = null;
while ((line = reader.readLine()) != null) {
parserLine(line);
}
// 全部解析完后,设置info
lrcinfo.setInfos(maps);
return lrcinfo;
}
/**
* 利用正则表达式解析每行具体语句
* 并在解析完该语句后,将解析出来的信息设置在LrcInfo对象中
*
* @param str
*/
private void parserLine(String str) {
// 取得歌曲名信息
if (str.startsWith("[ti:")) {
String title = str.substring(4, str.length() - 1);
System.out.println("title--->" + title);
lrcinfo.setTitle(title);
}// 取得歌手信息
else if (str.startsWith("[ar:")) {
String singer = str.substring(4, str.length() - 1);
System.out.println("singer--->" + singer);
lrcinfo.setSinger(singer);
}// 取得专辑信息
else if (str.startsWith("[al:")) {
String album = str.substring(4, str.length() - 1);
System.out.println("album--->" + album);
lrcinfo.setAlbum(album);
}// 通过正则取得每句歌词信息
else {
// 设置正则规则
String reg = "\\[(\\d{2}:\\d{2}\\.\\d{2})\\]";
// 编译
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(str);
// 如果存在匹配项,则执行以下操作
while (matcher.find()) {
// 得到匹配的所有内容
String msg = matcher.group();
// 得到这个匹配项开始的索引
int start = matcher.start();
// 得到这个匹配项结束的索引
int end = matcher.end();
// 得到这个匹配项中的组数
int groupCount = matcher.groupCount();
// 得到每个组中内容
for (int i = 0; i <= groupCount; i++) {
String timeStr = matcher.group(i);
if (i == 1) {
// 将第二组中的内容设置为当前的一个时间点
currentTime = strToLong(timeStr);
}
}
// 得到时间点后的内容
String[] content = pattern.split(str);
// 输出数组内容
for (int i = 0; i < content.length; i++) {
if (i == content.length - 1) {
// 将内容设置为当前内容
currentContent = content[i];
}
}
// 设置时间点和内容的映射
maps.put(currentTime, currentContent);
System.out.println("put---currentTime--->" + currentTime
+ "----currentContent---->" + currentContent);
}
}
}
/**
* 将解析得到的表示时间的字符转化为Long型
*
* @param group
* 字符形式的时间点
* @return Long形式的时间
*/
private long strToLong(String timeStr) {
// 因为给如的字符串的时间格式为XX:XX.XX,返回的long要求是以毫秒为单位
// 1:使用:分割 2:使用.分割
String[] s = timeStr.split(":");
int min = Integer.parseInt(s[0]);
String[] ss = s[1].split("\\.");
int sec = Integer.parseInt(ss[0]);
int mill = Integer.parseInt(ss[1]);
return min * 60 * 1000 + sec * 1000 + mill * 10;
}
public static void main(String[] args) {
LrcParser lp = new LrcParser();
try {
lp.parser("G:\\WebRoot\\a1.lrc");
} catch (Exception e) {
System.out.println("parser erro");
e.printStackTrace();
}
}
}
以上代码难度都不大
个人觉得
正则表达式其实并不难
只是因为有很多不规则符号堆叠在一起
让我们直观的很难理解
掌握符号规则后
还是挺好用的
正则表达在J***A中都被封装在
regex包下面
主要是Pattern类与Matcher类
其实我个人在掌握了正则的基本概念后
用J***A写这个代码却花了不少时间
主要是对这两个对象中的一些方法理解错误
以下简单总结下
两个类中易理解错的方法
Matcher对象中
matcher()方法是匹配整个字符串
lookingat()是匹配字符串的开头
find()是查找字符串中能否匹配
使用find()方法
得到一个字符串中的匹配后
matcher.start()得到这个匹配的startIndex
matcher.end()得到这个匹配的endIndex
matcher.group()能得到满足匹配的全部内容(最大的一个组)
matcher.groupCount()能得到当前匹配中的组数------(在正则中用()包围起来的一个部分算一个单独的组)
marcher.group(i) 得到指定的某个组的内容
又通过matcher.find()
我们可能在某一行可以得到多个匹配结果
每当调用一次matcher.find()
当前匹配对象就自动换为下个匹配成功对象
要遍历所有匹配结果
Java代码
//遍历每个匹配成功对象<br>while (matcher.find()) {<br> //对每一个匹配对象的操作
<br> // 得到匹配的所有内容
String msg = matcher.group();
// 得到这个匹配项开始的索引
int start = matcher.start();
// 得到这个匹配项结束的索引
int end = matcher.end();
// 得到这个匹配项中的组数
int groupCount = matcher.groupCount();
// 得到每个组中内容
for (int i = 0; i <= groupCount; i++) {
String timeStr = matcher.group(i);
if (i == 1) {
// 将第二组中的内容设置为当前的一个时间点
currentTime = strToLong(timeStr);
}
}
// 得到时间点后的内容
String[] content = pattern.split(str);
// 输出数组内容
for (int i = 0; i < content.length; i++) {
if (i == content.length - 1) {
// 将内容设置为当前内容
currentContent = content[i];
}
}
http://java-mzd.iteye.com/blog/811374
一起写android中的Mp3播放器
真是受益匪浅
再次感谢老师的无私奉献
不过其中问题也确实不少
感觉老师的代码重构做的不够
其中对LRC文件的解析也弄的比较马虎
今天特意花了一天的时间
好好研究了正则表达式
也仔细思索了LRC文件到底应该怎么来解析
以下先分析思路
再给出实现代码
首先
我们应该明白LRC文件的组成
LRC文件本质就是个符合一定格式规范的文本文件
这一点对照XML文件就很好理解了
一个LRC文件的组成
通常由以下几个部分组成
[ti:约定]-------标题
[ar:周惠]------演唱者
[al:周蕙-精选]-------专辑
[00:26.00]远处的钟声回荡在雨里--------每句内容由一个时间点和内容组成
同时应该注意到
[02:23.00][00:49.00]一路从泥泞走到了美景---------在每个内容可能出现多个时间点
然后
我们 用一个实体类
LrcInfo
来封装每个Lrc文件的具体内容
Java代码
package javamzd.mp3player.Info;
import java.util.HashMap;
/**
* 用来封装歌词信息的类
* @author Administrator
*
*/
public class LrcInfo {
private String title;//歌曲名
private String singer;//演唱者
private String album;//专辑
private HashMap<Long,String> infos;//保存歌词信息和时间点一一对应的Map
//以下为getter() setter()
}
3.读入Lrc文件,开始逐行解析
解析步骤:
1.读入文件
2.封装为BufferedReader对象
3.调用readline()方法逐行读取数据,得到String str
4.用parser()方法解析每一条具体的String语句
5.每句解析完后,将得到的内容在LrcInfo对象中进行设置
Java代码
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 此类用来解析LRC文件 将解析完整的LRC文件放入一个LrcInfo对象中 并且返回这个LrcInfo对象s author:java_mzd
*/
public class LrcParser {
private LrcInfo lrcinfo = new LrcInfo();
private long currentTime = 0;//存放临时时间
private String currentContent = null;//存放临时歌词
private Map<Long, String> maps = new HashMap<Long, String>();//用户保存所有的歌词和时间点信息间的映射关系的Map
/**
* 根据文件路径,读取文件,返回一个输入流
*
* @param path
* 路径
* @return 输入流
* @throws FileNotFoundException
*/
private InputStream readLrcFile(String path) throws FileNotFoundException {
File f = new File(path);
InputStream ins = new FileInputStream(f);
return ins;
}
public LrcInfo parser(String path) throws Exception {
InputStream in = readLrcFile(path);
lrcinfo = parser(in);
return lrcinfo;
}
/**
* 将输入流中的信息解析,返回一个LrcInfo对象
*
* @param inputStream
* 输入流
* @return 解析好的LrcInfo对象
* @throws IOException
*/
public LrcInfo parser(InputStream inputStream) throws IOException {
// 三层包装
InputStreamReader inr = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inr);
// 一行一行的读,每读一行,解析一行
String line = null;
while ((line = reader.readLine()) != null) {
parserLine(line);
}
// 全部解析完后,设置info
lrcinfo.setInfos(maps);
return lrcinfo;
}
/**
* 利用正则表达式解析每行具体语句
* 并在解析完该语句后,将解析出来的信息设置在LrcInfo对象中
*
* @param str
*/
private void parserLine(String str) {
// 取得歌曲名信息
if (str.startsWith("[ti:")) {
String title = str.substring(4, str.length() - 1);
System.out.println("title--->" + title);
lrcinfo.setTitle(title);
}// 取得歌手信息
else if (str.startsWith("[ar:")) {
String singer = str.substring(4, str.length() - 1);
System.out.println("singer--->" + singer);
lrcinfo.setSinger(singer);
}// 取得专辑信息
else if (str.startsWith("[al:")) {
String album = str.substring(4, str.length() - 1);
System.out.println("album--->" + album);
lrcinfo.setAlbum(album);
}// 通过正则取得每句歌词信息
else {
// 设置正则规则
String reg = "\\[(\\d{2}:\\d{2}\\.\\d{2})\\]";
// 编译
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(str);
// 如果存在匹配项,则执行以下操作
while (matcher.find()) {
// 得到匹配的所有内容
String msg = matcher.group();
// 得到这个匹配项开始的索引
int start = matcher.start();
// 得到这个匹配项结束的索引
int end = matcher.end();
// 得到这个匹配项中的组数
int groupCount = matcher.groupCount();
// 得到每个组中内容
for (int i = 0; i <= groupCount; i++) {
String timeStr = matcher.group(i);
if (i == 1) {
// 将第二组中的内容设置为当前的一个时间点
currentTime = strToLong(timeStr);
}
}
// 得到时间点后的内容
String[] content = pattern.split(str);
// 输出数组内容
for (int i = 0; i < content.length; i++) {
if (i == content.length - 1) {
// 将内容设置为当前内容
currentContent = content[i];
}
}
// 设置时间点和内容的映射
maps.put(currentTime, currentContent);
System.out.println("put---currentTime--->" + currentTime
+ "----currentContent---->" + currentContent);
}
}
}
/**
* 将解析得到的表示时间的字符转化为Long型
*
* @param group
* 字符形式的时间点
* @return Long形式的时间
*/
private long strToLong(String timeStr) {
// 因为给如的字符串的时间格式为XX:XX.XX,返回的long要求是以毫秒为单位
// 1:使用:分割 2:使用.分割
String[] s = timeStr.split(":");
int min = Integer.parseInt(s[0]);
String[] ss = s[1].split("\\.");
int sec = Integer.parseInt(ss[0]);
int mill = Integer.parseInt(ss[1]);
return min * 60 * 1000 + sec * 1000 + mill * 10;
}
public static void main(String[] args) {
LrcParser lp = new LrcParser();
try {
lp.parser("G:\\WebRoot\\a1.lrc");
} catch (Exception e) {
System.out.println("parser erro");
e.printStackTrace();
}
}
}
以上代码难度都不大
个人觉得
正则表达式其实并不难
只是因为有很多不规则符号堆叠在一起
让我们直观的很难理解
掌握符号规则后
还是挺好用的
正则表达在J***A中都被封装在
regex包下面
主要是Pattern类与Matcher类
其实我个人在掌握了正则的基本概念后
用J***A写这个代码却花了不少时间
主要是对这两个对象中的一些方法理解错误
以下简单总结下
两个类中易理解错的方法
Matcher对象中
matcher()方法是匹配整个字符串
lookingat()是匹配字符串的开头
find()是查找字符串中能否匹配
使用find()方法
得到一个字符串中的匹配后
matcher.start()得到这个匹配的startIndex
matcher.end()得到这个匹配的endIndex
matcher.group()能得到满足匹配的全部内容(最大的一个组)
matcher.groupCount()能得到当前匹配中的组数------(在正则中用()包围起来的一个部分算一个单独的组)
marcher.group(i) 得到指定的某个组的内容
又通过matcher.find()
我们可能在某一行可以得到多个匹配结果
每当调用一次matcher.find()
当前匹配对象就自动换为下个匹配成功对象
要遍历所有匹配结果
Java代码
//遍历每个匹配成功对象<br>while (matcher.find()) {<br> //对每一个匹配对象的操作
<br> // 得到匹配的所有内容
String msg = matcher.group();
// 得到这个匹配项开始的索引
int start = matcher.start();
// 得到这个匹配项结束的索引
int end = matcher.end();
// 得到这个匹配项中的组数
int groupCount = matcher.groupCount();
// 得到每个组中内容
for (int i = 0; i <= groupCount; i++) {
String timeStr = matcher.group(i);
if (i == 1) {
// 将第二组中的内容设置为当前的一个时间点
currentTime = strToLong(timeStr);
}
}
// 得到时间点后的内容
String[] content = pattern.split(str);
// 输出数组内容
for (int i = 0; i < content.length; i++) {
if (i == content.length - 1) {
// 将内容设置为当前内容
currentContent = content[i];
}
}
http://java-mzd.iteye.com/blog/811374
相关文章推荐
- java中用正则表达式解析LRC文件
- Java使用正则表达式解析LRC歌词文件
- java中用正则表达式解析LRC文件
- 用正则表达式和java解析csv文件
- 用正则表达式和java解析csv文件
- java正则表达式练习之分析lrc文件
- java读取txt文件,使用正则表达式获取信息
- 正则表达式练习: android 歌词解析lrc 转 txt 代码
- java流与文件——正则表达式
- java正则表达式的应用 java读取文件并获取电话号码
- Java基于正则表达式实现xml文件的解析功能详解
- Java之正则表达式【实例解析】
- Java 通过正则表达式实现简单xml文件解析
- 用java开发编译器之Thompson构造:正则表达式的词法解析
- JAVA高级【1.7】《Java核心技术2》流与文件-正则表达式
- Java 对象序列化和操作文件 正则表达式
- 3、java设置Linux系统时间之 正则表达式解析时间 及总结
- Java正则表达式的多行匹配实战-将java文件中的单行和多行注释内容替换为空
- JAVA学习笔记Day09——JAVA用正则表达式简单解析
- 用正则表达式解析C#文件(updated)