欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C#解析Lrc歌词文件过程详解

程序员文章站 2023-11-14 08:45:58
看到很多人解析歌词文件时写了一大片的字符处理代码,而且看得不是很明白,所以自己研究了一下,  首先来了解下lrc文件  时间格式:  1...

看到很多人解析歌词文件时写了一大片的字符处理代码,而且看得不是很明白,所以自己研究了一下,
 首先来了解下lrc文件
 时间格式:
 1、标准格式: [分钟:秒.毫秒] 歌词
 注释:括号、冒号、点号全都要求英文输入状态;
 2、其他格式①:[分钟:秒] 歌词;
 3、其他格式②:[分钟:秒:毫秒] 歌词,与标准格式相比,秒后边的点号被改成了冒号。

标准格式:
 其格式为"[标识名:值]"。大小写等价。以下是预定义的标签。
[ar:艺人名]
[ti:曲名]
[al:专辑名] 
[by:编者(指编辑lrc歌词的人)] 
[offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。
标准好啊,我就按照标准来做了 

 public class lrc
 {
  /// <summary>
  /// 歌曲
  /// </summary>
  public string title { get; set; }
  /// <summary>
  /// 艺术家
  /// </summary>
  public string artist { get; set; }
  /// <summary>
  /// 专辑
  /// </summary>
  public string album { get; set; }
  /// <summary>
  /// 歌词作者
  /// </summary>
  public string lrcby { get; set; }
  /// <summary>
  /// 偏移量
  /// </summary>
  public string offset { get; set; }

  /// <summary>
  /// 歌词
  /// </summary>
  public dictionary<double, string> lrcword = new dictionary<double, string>();

  /// <summary>
  /// 获得歌词信息
  /// </summary>
  /// <param name="lrcpath">歌词路径</param>
  /// <returns>返回歌词信息(lrc实例)</returns>
  public static lrc initlrc(string lrcpath)
  {
   lrc lrc = new lrc();
   using (filestream fs = new filestream(lrcpath, filemode.open, fileaccess.read, fileshare.read))
   {
    string line;
    using (streamreader sr = new streamreader(fs, encoding.default))
    {
     while ((line = sr.readline()) != null)
     {
      if (line.startswith("[ti:"))
      {
       lrc.title = splitinfo(line);
      }
      else if (line.startswith("[ar:"))
      {
       lrc.artist = splitinfo(line);
      }
      else if (line.startswith("[al:"))
      {
       lrc.album = splitinfo(line);
      }
      else if (line.startswith("[by:"))
      {
       lrc.lrcby = splitinfo(line);
      }
      else if (line.startswith("[offset:"))
      {
       lrc.offset = splitinfo(line);
      }
      else
      {
       regex regex = new regex(@"\[([0-9.:]*)\]+(.*)", regexoptions.compiled);
       matchcollection mc = regex.matches(line);
       double time = timespan.parse("00:" + mc[0].groups[1].value).totalseconds;
       string word = mc[0].groups[2].value;
       lrc.lrcword.add(time, word);
      }
     }
    }
   } 
   return lrc;
  }

  /// <summary>
  /// 处理信息(私有方法)
  /// </summary>
  /// <param name="line"></param>
  /// <returns>返回基础信息</returns>
  static string splitinfo(string line)
  {
   return line.substring(line.indexof(":") + 1).trimend(']');
  }
 }

一行代码:lrc lrc= lrc.initlrc("test.lrc"); 

我将分离好的歌词放入了dictionary<double, string>里,当然也可以直接用数组存,格式就要看实际的用途了,把这些都交给timespan来做吧。 
测试: 

C#解析Lrc歌词文件过程详解

C#解析Lrc歌词文件过程详解

很久以前有人提出了这个问题:一行歌词里面有多个时间会报错,这么久了也没见人把好的方案提供出来,今天我花了点时间,修改了下,下面是获取歌词方法 

 

/// <summary>
  /// 获得歌词信息
  /// </summary>
  /// <param name="lrcpath">歌词路径</param>
  /// <returns>返回歌词信息(lrc实例)</returns>
  public static lrc initlrc(string lrcpath)
  {
   lrc lrc = new lrc();
   dictionary<double, string> dicword = new dictionary<double, string>();
   using (filestream fs = new filestream(lrcpath, filemode.open, fileaccess.read, fileshare.read))
   {
    string line;
    using (streamreader sr = new streamreader(fs, encoding.default))
    {
     while ((line = sr.readline()) != null)
     {
      if (line.startswith("[ti:"))
      {
       lrc.title = splitinfo(line);
      }
      else if (line.startswith("[ar:"))
      {
       lrc.artist = splitinfo(line);
      }
      else if (line.startswith("[al:"))
      {
       lrc.album = splitinfo(line);
      }
      else if (line.startswith("[by:"))
      {
       lrc.lrcby = splitinfo(line);
      }
      else if (line.startswith("[offset:"))
      {
       lrc.offset = splitinfo(line);
      }
      else
      {
       try
       {
        regex regexword = new regex(@".*\](.*)");
        match mcw = regexword.match(line);
        string word = mcw.groups[1].value;
        regex regextime = new regex(@"\[([0-9.:]*)\]", regexoptions.compiled);
        matchcollection mct = regextime.matches(line);
        foreach (match item in mct)
        {
         double time = timespan.parse("00:" + item.groups[1].value).totalseconds;
         dicword.add(time, word);
        }
       }
       catch
       {
        continue;
       }
      }
     }
    }
   }
   lrc.lrcword = dicword.orderby(t => t.key).todictionary(t => t.key, p => p.value);
   return lrc;
  }

C#解析Lrc歌词文件过程详解

C#解析Lrc歌词文件过程详解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。