Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 746|回复: 0

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

[复制链接]

该用户从未签到

发表于 2011-9-18 13:15:59 | 显示全部楼层 |阅读模式
今天特意花了一天的时间

好好研究了正则表达式

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

以下先分析思路

再给出实现代码

首先

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

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

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

一个LRC文件的组成

通常由以下几个部分组成

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

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

然后

我们 用一个实体类

LrcInfo

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


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对象中进行设置



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;
                    }
                }
                // 设置时间点和内容的映射
                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();
        }
   
    }
}
                        
以上代码难度都不大

个人觉得

正则表达式其实并不难

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

让我们直观的很难理解

掌握符号规则后

还是挺好用的

正则表达在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()

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

要遍历所有匹配结果

//遍历每个匹配成功对象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;
                    }
                }
最后

我们解析完LRC文件后

在播放Mp3时

只需要根据播放时间

取出HashMap中的内容进行显示即可
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2024-6-7 12:08 , Processed in 0.372990 second(s), 48 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表