Lrc歌词解析器0.0.1.0

1. 类图
Lrc歌词解析器0.0.1.0_第1张图片
2. 源码清单
/**
* 文件名:LrcAnalyst.java
* 环境: GNU/Linux Ubuntu 7.04 + Eclipse 3.2 + JDK 1.6
* 功能:解析Lrc歌词文件,这只是一个在CLI下的Demo
* 版本:0.0.1.0
* 作者:88250
* 日期:2007.4.22
* E-mail & MDN: [email protected]
* QQ:845765
*/

import  java.io. * ;
import  java.util. * ;


/**
* 歌词解释类,用于对lrc歌词文件的解析
*/
public   class  LrcAnalyst
{
    
/**
     * lrc文件缓冲区
     
*/
    
private   static  Vector lyrics;

    
/**
     * 格式化好的歌词时间与索引,格式参考TimeAndIndex类
     
*/
    
private   static  Vector lrcTimeValAndIndex;

    
/**
     * 歌词的实际内容
     
*/
    
private   static  Vector lyrcisContent;
   
    
/**
         * 时间标签的长度,用于区分时间标签的格式
         *
         * 
@see  private float computeTimeTag(String timeStr)方法
         
*/
    
private   int  timeTagLength;
   
    
/**
     * 真正的歌词内容开始到lrc文本开头的偏移量
     
*/
    
private   int  realLyrcisStartOffset;
   
    
/**
     * 返回真正的歌词内容开始到lrc文本开头的偏移量
     * 
@return  偏移量
     
*/
    
public   int  getRealLrcStartOffset()
    {
    
return  realLyrcisStartOffset;
    }
   
    
/**
     * 是否确定了歌词标签的格式,确定的话是<code>true</code>, 否则是<code>false</code>
     * 
@see  private float computeTimeTag(String timeStr)方法
     
*/
    
private   boolean  isConfirmTimeTagLeng;
   
    
/**
         * 歌词解析器的默认构造器 <br>
         * 初始化歌词文件缓冲等字段
         
*/
    
public  LrcAnalyst()
    {
    lyrics 
=   new  Vector();
    lrcTimeValAndIndex 
=   new  Vector();
    lyrcisContent 
=   new  Vector();
    timeTagLength 
=   0 ;
    isConfirmTimeTagLeng 
=   false ;
    realLyrcisStartOffset 
=   0 ;
    }

    
/**
         * 按行对去读取文本文件内容
         * 
@param  fileName
         *                文件路径与文件名
         * 
@throws  IOException
         
*/
    
public   void  readFile(String fileName)
    {
    
try
    {
        InputStream r 
=   new  FileInputStream(fileName);
        ByteArrayOutputStream byteout 
=   new  ByteArrayOutputStream();
        
byte  tmp[]  =   new   byte [ 1024 ];
        
byte  context[];
      
        r.read(tmp);
        byteout.write(tmp);
        context 
=  byteout.toByteArray();
        String str 
=   new  String(context,  " GBK " );
        String lyrcisText[] 
=  str.split( " " );
        
        
for  ( int  i  =   0 ; i  <  lyrcisText.length; i ++ )
        {
        lyrics.add(lyrcisText);
        }
    }
    
catch  (IOException e)
    {
        e.printStackTrace();
    }
    }

    
/**
     * 显示读取lrc里的所有内容到控制台
     
*/
    
public   void  displayLrcContent()
    {
    
for  ( int  i  =   0 ; i  <  lyrics.size(); i ++ )
    {
        System.out.println(lyrics.get(i));
    }
    }

    
/**
     * 从文件缓冲lyrics Vector里进行歌词文件内容的解析,并将解析结果保存 <br>
     * 解析方法: <br>
     * Step0. 用']'分割一行内容到String[]
     * Step1. 查看每一行在第3个char是否是':' <br>
     * Step2. 查看每一行在第6个char是否是'.' <br>
     * Step3. 确定为歌词行,确定该lrc用的格式 <br>
     * <b>注意:目前,时间标签的格式有两种,分别是长度为8和5的</b> <br>
     * Step4. 循环直到歌词缓冲结束 <br>
     * <b>注意:这个算法可能存在严重缺陷<b>
     * 
@see  关于时间标签的格式,参考TimeTag类
     
*/
    
public   void  parseLyrics()
    {
    
for  ( int  i  =   0 ; i  <  lyrics.size(); i ++ )
    {
        String aLineLyrics 
=  (String) lyrics.get(i);
        String[] partsLrc 
=  aLineLyrics.split( " ] " );
        
        
char  flag1  =   0 ;
        
char  flag2  =   0 ;
        
if  ( ! aLineLyrics.isEmpty())
        {
//  很多制作lrc文件的人不负责,乱搞格式!!!!
        flag1  =  aLineLyrics.charAt( 1 );
        flag2 
=  aLineLyrics.charAt( 3 );
        }
        
        
if  ((aLineLyrics.length()  >   3 )
            
&&  (flag1  >=   48   &&  flag1  <=   57 )
            
&&  ( ' : '   ==  flag2))
        {
//  确定为歌词内容行
         if  ( ! isConfirmTimeTagLeng  &&  aLineLyrics.length()  >   9 )
        {
            
if  (aLineLyrics.charAt( 9 ==   ' ] ' )
            {
//  长度为8的时间标签格式
            timeTagLength  =   8 ;
            }
            
else   if  (aLineLyrics.charAt( 6 ==   ' ] ' )
            {
//  长度为5的时间标签格式
            timeTagLength  =   5 ;
            }
            realLyrcisStartOffset 
=  i;
            isConfirmTimeTagLeng 
=   true ;
        }
        
        
for  ( int  j  =   0 ; j  <  partsLrc.length; j ++ )
        {
            
if  (partsLrc[j].charAt( 0 ==   ' [ ' )
            {
//  确定为时间标签部分,而不是歌词内容部分
            String timeTagStr  =  partsLrc[j].substring( 1 , timeTagLength + 1 );
            
float  timeValue  =  computeTimeTag(timeTagStr);
            
//  添加歌词时间于对应的歌词索引
            lrcTimeValAndIndex.add( new  LrcTimeAndIndex(timeValue, i));
            }
            
else      //  如果歌词开头的内容也是'['将出现FATAL ERROR
            { //  确定为歌词内容部分
            lyrcisContent.add(partsLrc[j]);
            }
        }
        }
    }
    sortByTimeTag();
    }
   
    
/**
         * 
@param  timeStr
         *                表示歌词显示时间的String <br>
         *                例如:<br>
         *                "02:03.30"表示2*60s+3.3s=123.3s=1233ms的时刻 <br>
         *                <b>注意:考虑到歌曲长度不会很长,所以算法中直接取前两位作为分钟, <br>
         *                而从':'后的单位是秒。但是应为现在lrc文件格式不是很统一,例如: <br>
         *                "02:03"表示2*60s+3s=123s=1230ms,这是短格式表示,也要考虑到。 <br>
         *                目前,将时间标签分为的两种格式,长度分别为8,5
         * 
@return  计算好的时间值
         
*/
    
private   float  computeTimeTag(String timeStr)
    {
    
int  minutes  =  Integer.parseInt(timeStr.substring( 0 2 ));     //  取得分钟
     float  seconds  =   0 ;
   
    
if  (timeStr.length()  ==   8 )
    {
        seconds 
=  Float.parseFloat(timeStr.substring( 3 8 ));     //  取得秒钟
    }
    
else   if  (timeStr.length()  ==   5 )
    {
        seconds 
=  Float.parseFloat(timeStr.substring( 3 5 ));
    }

    
return  (minutes  *   60   +  seconds);     //  返回时间值
    }

    
/**
     * 更具歌词显示的先后时间顺序进行排序的标准
     
*/
    
private   void  sortByTimeTag()
    {
    Collections.sort(lrcTimeValAndIndex, 
new  Comparator()
    {
        
//  Parameters:
        
//  o1 - the first object to be compared.
        
//  o2 - the second object to be compared.
        
//  Returns:
        
//  a negative integer, zero, or a positive integer as the first
        
//  argument is less than, equal to, or greater than the second.
        
//  Throws:
        
//  ClassCastException - if the arguments' types prevent them from
        
//  being compared by this Comparator.
         public   int  compare(Object o1, Object o2)
        {
        LrcTimeAndIndex fl1 
=  (LrcTimeAndIndex) o1;
        LrcTimeAndIndex fl2 
=  (LrcTimeAndIndex) o2;

        
if  (fl1.getLrcTime()  -  fl2.getLrcTime()  >   0 )
        {
            
return   1 ;
        }
        
else   if  (fl1.getLrcTime()  -  fl2.getLrcTime()  >   0 )
        {
            
return   - 1 ;
        }
        
else
        {
            
return   0 ;
        }
        }

    });
    }

    
public   void  dispalyLrc()
    {
   
    }
    
/**
     * 主程序入口点
     *
     * 
@param  args
     *                命令行参数,这里没用到,为<code>null</code>
     
*/
    
public   static   void  main(String[] args)
    {
    LrcAnalyst lrcAnalyst 
=   new  LrcAnalyst();
    lrcAnalyst.readFile(
" 灰色的心.lrc " );
   
    lrcAnalyst.parseLyrics();

    Date startTime 
=   new  Date();

    
for  ( int  i  =   0 ; i  <  lrcTimeValAndIndex.size(); i ++ )
    {
        
while  ( true )
        {
        
try
        {
            Thread.currentThread().sleep(
500 );
            Date currentTime 
=   new  Date();
            LrcTimeAndIndex fl 
=  (LrcTimeAndIndex) (lrcTimeValAndIndex.get(i));
            
float  diffTime  =  currentTime.getTime()
                
-  startTime.getTime();
            
            
if  (fl.getLrcTime()  -  ( float ) diffTime  /   1000   <   0.0 )
            {
            System.out.println((String)lyrcisContent.get(fl.getLrcIndex() 
-  lrcAnalyst.getRealLrcStartOffset()));
            
break ;
            }
        }
        
catch  (Exception e)
        {
            e.printStackTrace();
        }
        }
    }
    }
}

/**
@author    daniel
*/
class  LrcTimeAndIndex
{
    
/**
     * 该行歌词的显示时间
     
*/
    
private   float  lrcTime;

    
/**
     * 该行歌词行索引
     
*/
    
private   int  lrcIndex;

    
/**
     * 默认的构造器
     
*/
    
public  LrcTimeAndIndex()
    {

    }

    
/**
     * 带参数的构造器,设置时间标签和对应的歌词行索引
     * 
@param  lrcTime 时间标签
     * 
@param  lrcIndex 歌词行索引
     
*/
    
public  LrcTimeAndIndex( float  lrcTime,  int  lrcIndex)
    {
    
this .lrcTime  =  lrcTime;
    
this .lrcIndex  =  lrcIndex;
    }

    
/**
     * 返回歌词应该出现的时间
     * 
@return    lrcTime 出现时间
     * @uml.property   name="lrcTime"
     
*/
    
public   float  getLrcTime()
    {
    
return  lrcTime;
    }

    
/**
     * 返回歌词内容行索引
     * 
@return    歌词内容行索引
     * @uml.property   name="lrcIndex"
     
*/
    
public   int  getLrcIndex()
    {
    
return  lrcIndex;
    }
}
 
3. 工程文件下载
     LrcAnalyst0.0.1.0 by eclipse 3.2.0

4. 版本升级
    更新版本请访问 LrcAnalyst0.0.2.0

你可能感兴趣的:(Lrc歌词解析器0.0.1.0)