java中用正则表达式解析LRC文件

跟着Mars老师

一起写android中的Mp3播放器

真是受益匪浅

再次感谢老师的无私奉献

 

 

不过其中问题也确实不少

感觉老师的代码重构做的不够

其中对LRC文件的解析也弄的比较马虎

 

 今天特意花了一天的时间

好好研究了正则表达式

也仔细思索了LRC文件到底应该怎么来解析

 

以下先分析思路

再给出实现代码

 

首先

我们应该明白LRC文件的组成 

LRC文件本质就是个符合一定格式规范的文本文件

这一点对照XML文件就很好理解了

一个LRC文件的组成

通常由以下几个部分组成

[ti:约定]-------标题
[ar:周惠]------演唱者
[al:周蕙-精选]-------专辑
[00:26.00]远处的钟声回荡在雨里--------每句内容由一个时间点和内容组成

同时应该注意到
[02:23.00][00:49.00]一路从泥泞走到了美景---------在每个内容可能出现多个时间点  

 

然后

我们 用一个实体类

LrcInfo

来封装每个Lrc文件的具体内容

Java代码   收藏代码
  1. package javamzd.mp3player.Info;  
  2.   
  3. import java.util.HashMap;  
  4.   
  5. /** 
  6.  * 用来封装歌词信息的类 
  7.  * @author Administrator 
  8.  * 
  9.  */  
  10. public class LrcInfo {  
  11.     private String title;//歌曲名  
  12.     private String singer;//演唱者  
  13.     private String album;//专辑     
  14.     private HashMap<Long,String> infos;//保存歌词信息和时间点一一对应的Map  
  15.    //以下为getter()  setter()  
  16.       
  17. }  

 

3.读入Lrc文件,开始逐行解析

   解析步骤:

     1.读入文件

     2.封装为BufferedReader对象

     3.调用readline()方法逐行读取数据,得到String str

     4.用parser()方法解析每一条具体的String语句

     5.每句解析完后,将得到的内容在LrcInfo对象中进行设置

 

Java代码   收藏代码
  1. import java.io.BufferedReader;  
  2. import java.io.File;  
  3. import java.io.FileInputStream;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.InputStreamReader;  
  8. import java.util.HashMap;  
  9. import java.util.Map;  
  10. import java.util.regex.Matcher;  
  11. import java.util.regex.Pattern;  
  12.   
  13. /** 
  14.  * 此类用来解析LRC文件 将解析完整的LRC文件放入一个LrcInfo对象中 并且返回这个LrcInfo对象s author:java_mzd 
  15.  */  
  16. public class LrcParser {  
  17.     private LrcInfo lrcinfo = new LrcInfo();  
  18.       
  19.     private long currentTime = 0;//存放临时时间  
  20.     private String currentContent = null;//存放临时歌词  
  21.     private Map<Long, String> maps = new HashMap<Long, String>();//用户保存所有的歌词和时间点信息间的映射关系的Map  
  22.   
  23.   
  24.   
  25.     /** 
  26.      * 根据文件路径,读取文件,返回一个输入流 
  27.      *  
  28.      * @param path 
  29.      *            路径 
  30.      * @return 输入流 
  31.      * @throws FileNotFoundException 
  32.      */  
  33.     private InputStream readLrcFile(String path) throws FileNotFoundException {  
  34.         File f = new File(path);  
  35.         InputStream ins = new FileInputStream(f);  
  36.         return ins;  
  37.     }  
  38.   
  39.     public LrcInfo parser(String path) throws Exception {  
  40.         InputStream in = readLrcFile(path);  
  41.         lrcinfo = parser(in);  
  42.         return lrcinfo;  
  43.   
  44.     }  
  45.       
  46.     /** 
  47.      * 将输入流中的信息解析,返回一个LrcInfo对象 
  48.      *  
  49.      * @param inputStream 
  50.      *            输入流 
  51.      * @return 解析好的LrcInfo对象 
  52.      * @throws IOException 
  53.      */  
  54.     public LrcInfo parser(InputStream inputStream) throws IOException {  
  55.         // 三层包装  
  56.         InputStreamReader inr = new InputStreamReader(inputStream);  
  57.         BufferedReader reader = new BufferedReader(inr);  
  58.         // 一行一行的读,每读一行,解析一行  
  59.         String line = null;  
  60.         while ((line = reader.readLine()) != null) {  
  61.             parserLine(line);  
  62.         }  
  63.         // 全部解析完后,设置info  
  64.         lrcinfo.setInfos(maps);  
  65.         return lrcinfo;  
  66.     }  
  67.   
  68.     /** 
  69.      * 利用正则表达式解析每行具体语句 
  70.      * 并在解析完该语句后,将解析出来的信息设置在LrcInfo对象中 
  71.      *  
  72.      * @param str 
  73.      */  
  74.     private void parserLine(String str) {  
  75.         // 取得歌曲名信息  
  76.         if (str.startsWith("[ti:")) {  
  77.             String title = str.substring(4, str.length() - 1);  
  78.             System.out.println("title--->" + title);  
  79.             lrcinfo.setTitle(title);  
  80.   
  81.         }// 取得歌手信息  
  82.         else if (str.startsWith("[ar:")) {  
  83.             String singer = str.substring(4, str.length() - 1);  
  84.             System.out.println("singer--->" + singer);  
  85.             lrcinfo.setSinger(singer);  
  86.   
  87.         }// 取得专辑信息  
  88.         else if (str.startsWith("[al:")) {  
  89.             String album = str.substring(4, str.length() - 1);  
  90.             System.out.println("album--->" + album);  
  91.             lrcinfo.setAlbum(album);  
  92.   
  93.         }// 通过正则取得每句歌词信息  
  94.         else {  
  95.             // 设置正则规则  
  96.             String reg = "\\[(\\d{2}:\\d{2}\\.\\d{2})\\]";  
  97.             // 编译  
  98.             Pattern pattern = Pattern.compile(reg);  
  99.             Matcher matcher = pattern.matcher(str);  
  100.   
  101.             // 如果存在匹配项,则执行以下操作  
  102.             while (matcher.find()) {  
  103.                 // 得到匹配的所有内容  
  104.                 String msg = matcher.group();  
  105.                 // 得到这个匹配项开始的索引  
  106.                 int start = matcher.start();  
  107.                 // 得到这个匹配项结束的索引  
  108.                 int end = matcher.end();  
  109.   
  110.                 // 得到这个匹配项中的组数  
  111.                 int groupCount = matcher.groupCount();  
  112.                 // 得到每个组中内容  
  113.                 for (int i = 0; i <= groupCount; i++) {  
  114.                     String timeStr = matcher.group(i);  
  115.                     if (i == 1) {  
  116.                         // 将第二组中的内容设置为当前的一个时间点  
  117.                         currentTime = strToLong(timeStr);  
  118.                     }  
  119.                 }  
  120.   
  121.                 // 得到时间点后的内容  
  122.                 String[] content = pattern.split(str);  
  123.                 // 输出数组内容  
  124.                 for (int i = 0; i < content.length; i++) {  
  125.                     if (i == content.length - 1) {  
  126.                         // 将内容设置为当前内容  
  127.                         currentContent = content[i];  
  128.                     }  
  129.                 }  
  130.                 // 设置时间点和内容的映射  
  131.                 maps.put(currentTime, currentContent);  
  132.                 System.out.println("put---currentTime--->" + currentTime  
  133.                         + "----currentContent---->" + currentContent);  
  134.   
  135.             }  
  136.         }  
  137.     }  
  138.   
  139.     /** 
  140.      * 将解析得到的表示时间的字符转化为Long型 
  141.      *  
  142.      * @param group 
  143.      *            字符形式的时间点 
  144.      * @return Long形式的时间 
  145.      */  
  146.     private long strToLong(String timeStr) {  
  147.         // 因为给如的字符串的时间格式为XX:XX.XX,返回的long要求是以毫秒为单位  
  148.         // 1:使用:分割 2:使用.分割  
  149.         String[] s = timeStr.split(":");  
  150.         int min = Integer.parseInt(s[0]);  
  151.         String[] ss = s[1].split("\\.");  
  152.         int sec = Integer.parseInt(ss[0]);  
  153.         int mill = Integer.parseInt(ss[1]);  
  154.         return min * 60 * 1000 + sec * 1000 + mill * 10;  
  155.     }  
  156.   
  157.       
  158.     public static void main(String[] args) {  
  159.         LrcParser lp = new LrcParser();  
  160.          try {  
  161.             lp.parser("G:\\WebRoot\\a1.lrc");  
  162.         } catch (Exception e) {  
  163.        System.out.println("parser erro");  
  164.             e.printStackTrace();  
  165.         }  
  166.       
  167.     }  
  168. }  
 

 

以上代码难度都不大

个人觉得

正则表达式其实并不难

只是因为有很多不规则符号堆叠在一起

让我们直观的很难理解

掌握符号规则后

还是挺好用的

 

 

正则表达在JAVA中都被封装在

regex包下面

主要是Pattern类与Matcher类

 

 

其实我个人在掌握了正则的基本概念后

用JAVA写这个代码却花了不少时间

 

主要是对这两个对象中的一些方法理解错误

 

以下简单总结下

两个类中易理解错的方法

 

Matcher对象中

matcher()方法是匹配整个字符串
lookingat()是匹配字符串的开头
find()是查找字符串中能否匹配

 

使用find()方法

得到一个字符串中的匹配后

matcher.start()得到这个匹配的startIndex
matcher.end()得到这个匹配的endIndex

 

matcher.group()能得到满足匹配的全部内容(最大的一个组)


matcher.groupCount()能得到当前匹配中的组数------(在正则中用()包围起来的一个部分算一个单独的组)
marcher.group(i) 得到指定的某个组的内容

又通过matcher.find()

我们可能在某一行可以得到多个匹配结果

每当调用一次matcher.find()

当前匹配对象就自动换为下个匹配成功对象

 

要遍历所有匹配结果

Java代码   收藏代码
  1. //遍历每个匹配成功对象<br>while (matcher.find()) {<br>                     //对每一个匹配对象的操作  
  2. <br>                // 得到匹配的所有内容  
  3.                 String msg = matcher.group();  
  4.                 // 得到这个匹配项开始的索引  
  5.                 int start = matcher.start();  
  6.                 // 得到这个匹配项结束的索引  
  7.                 int end = matcher.end();  
  8.   
  9.                 // 得到这个匹配项中的组数  
  10.                 int groupCount = matcher.groupCount();  
  11.                 // 得到每个组中内容  
  12.                 for (int i = 0; i <= groupCount; i++) {  
  13.                     String timeStr = matcher.group(i);  
  14.                     if (i == 1) {  
  15.                         // 将第二组中的内容设置为当前的一个时间点  
  16.                         currentTime = strToLong(timeStr);  
  17.                     }  
  18.                 }  
  19.   
  20.                 // 得到时间点后的内容  
  21.                 String[] content = pattern.split(str);  
  22.                 // 输出数组内容  
  23.                 for (int i = 0; i < content.length; i++) {  
  24.                     if (i == content.length - 1) {  
  25.                         // 将内容设置为当前内容  
  26.                         currentContent = content[i];  
  27.                     }  
  28.                 } 
http://java-mzd.iteye.com/blog/811374
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值