排序和正则表达式的应用
来源:互联网 发布:高级编程语言就业前景 编辑:程序博客网 时间:2024/06/05 10:36
题目
为了实现一边播放歌曲,一边同步显示歌词,很多播放器会借助 lrc 文件。 播放器需要做两件事:
1. 将 lrc 文件中重复的文本展开,生成与单一时间标签对应的文本
2. 播放时将 1 中生成的文本随歌曲的播放一起滚动
例如:
[ti:两只老虎][ar:歌者盟][al:歌者盟翻唱专辑][by:][offset:700][00:00.74]两只老虎[00:08.34][00:24.26][00:40.26][00:56.23]两只老虎两只老虎 跑得快跑得快[00:16.39][00:32.37][00:48.16][01:04.37]一只没有耳朵 一只没有尾巴[00:20.28][00:36.19][00:52.29][01:08.15]真奇怪 真奇怪[00:05.52][00:39.83][01:12.28]
展开成
[ti:两只老虎][ar:歌者盟][al:歌者盟翻唱专辑][by:][offset:700][00:00.74]两只老虎[00:05.52] [00:08.34]两只老虎两只老虎 跑得快跑得快[00:16.39]一只没有耳朵 一只没有尾巴[00:20.28]真奇怪 真奇怪[00:24.26]两只老虎两只老虎 跑得快跑得快[00:32.37]一只没有耳朵 一只没有尾巴[00:36.19]真奇怪 真奇怪[00:39.83] [00:40.26]两只老虎两只老虎 跑得快跑得快[00:48.16]一只没有耳朵 一只没有尾巴[00:52.29]真奇怪 真奇怪[00:56.23]两只老虎两只老虎 跑得快跑得快[01:04.37]一只没有耳朵 一只没有尾巴[01:08.15]真奇怪 真奇怪[01:12.28]
实现思路
1. 将原始文件按照时间标签进行分割,分割成一个时间标签带0-1个内容
2. 将标题部分保留顺序输出
3. 将分割后的content按照时间标签排序后输出
储备知识:
正则表达式:
由于后期我们要进行时间标签的分割,所以需要了解正则表达式
所有的时间标签都是形如[00:08.34]
的格式,并且存在零个或者多个
而scala对正则表达式处理主要分以下几个步骤:
1. 构建Regex对象,可以调用String的.r
方法 : val timeFormat = """(\[\d\d:\d\d.\d\d\])(.*)""".r
2. 对Regex对象调用findAllIn
返回遍历所有匹配的迭代器: for (time ← timeFormat.findAllIn(times))
3. 如果需要匹配首个,则调用findFirstIn
:
val wsnumPatten = """\s+[0-9]+\s+""".rval m1 = wsnumPatten.findFirstIn("10 x, 20 y") //m1: Option[String] = Some( 20 )
这边因为10前面没有一个满足\s
的,所以20被首次发现并匹配
4. 如果字符串的开始是否能匹配,则用findPrefixOf
:
val wsnumPatten = """\s+[0-9]+\s+""".rval m1 = wsnumPatten.findPrefixOf("10 x, 20 y")val m2 = wsnumPatten.findPrefixOf(" 10 x, 20 y")//m1: Option[String] = None//m2: Option[String] = Some( 10 )
- 如果要替换首次匹配,则使用
replaceFirstIn
,,如果要匹配全部,则replaceAllIn
:
val wsnumPatten = """\s+[0-9]+\s+""".rval m1 = wsnumPatten.replaceFirstIn("10 x, 20 y","ctao")val m2 = wsnumPatten.replaceAllIn(" 10 x, 20 y","ctao")//m1: String = 10 x,ctaoy//m2: String = ctaox,ctaoy
- 正则表达式组则可以进行多个匹配,只需要在提取的子表达式的两侧加上圆括号:
val timer = """(\[\d\d:\d\d.\d\d\])(.*)""".rfor (timer(time, content) ← timer.findAllIn("[00:36.19]真奇怪 真奇怪")) println(s"time:$time,content:$content") //time:[00:36.19],content:真奇怪 真奇怪
显然,我们用第一个括号匹配了时间标签,第二个匹配了内容
而排序:主要就是一个实现了Ordered
特质的类可被排序
case class Line(time: String, content: String) extends Ordered[Line] { override def compare(that: Line): Int = if (stringTime2Double(time) > stringTime2Double(that.time)) 1 else if (stringTime2Double(time) < stringTime2Double(that.time)) -1 else 0 private def stringTime2Double(time: String): Double = { val timeFormat = """\[\d\d:\d\d.\d\d\]""".r assert(timeFormat.findAllIn(time).nonEmpty) time.mkString .split("\\[")(1).split("\\]")(0) .replace(":", "") .replace(".", "") .toDouble }
其实这边string2Double有点多余,后面会优化掉,这边主要就是实现了Ordered,因为在调用集合类的Sorted方法时需要
def sorted[B >: A](implicit ord : scala.math.Ordering[B])
基本储备够了我们看第一种实现:
package ctao.janimport scala.collection.mutable.ArrayBufferimport scala.io.Source/** * Created by ctao on 16-1-14. */object SongTest extends App { case class Line(time: String, content: String) extends Ordered[Line] { override def compare(that: Line): Int = if (stringTime2Double(time) > stringTime2Double(that.time)) 1 else if (stringTime2Double(time) < stringTime2Double(that.time)) -1 else 0 private def stringTime2Double(time: String): Double = { val timeFormat = """\[\d\d:\d\d.\d\d\]""".r assert(timeFormat.findAllIn(time).nonEmpty) time.mkString .split("\\[")(1).split("\\]")(0) .replace(":", "") .replace(".", "") .toDouble } } def inputLrc(path: String) = { val contentBuffer = ArrayBuffer[Line]() val titleBuffer = ArrayBuffer[String]() val timers = """(\[\d\d:\d\d.\d\d\].+\])(.*)""".r val timer = """(\[\d\d:\d\d.\d\d\])(.*)""".r val timeFormat = """\[\d\d:\d\d.\d\d\]""".r for (line ← Source.fromFile(path).getLines()) { line match { case timers(times, content) ⇒ for (time ← timeFormat.findAllIn(times)) contentBuffer += Line(time, content) case timer(time, content) ⇒ contentBuffer += Line(time, content) case title: String ⇒ titleBuffer += title } } (titleBuffer, contentBuffer) } def expend(path: String) = { val (titleBuffer, contentBuffer) = inputLrc(path) titleBuffer.foreach(println) for(x ← contentBuffer.sorted){ println(s"${x.time}${x.content}") } } expend("lrc")}
可以是可以了,但问题有几点:
1. Line的样例类有点多余
2. 用了可变集合类
所以后面对代码进行了优化,优化后的版本是:
package ctao.janimport scala.io.Source/** * Created by ctao on 16-1-14. */object SongTest extends App { def inputLrc(path: String) = { var contentList = List[(String, String)]() var titleList = List[String]() val timers = """(\[\d\d:\d\d.\d\d\].+\])(.*)""".r val timer = """(\[\d\d:\d\d.\d\d\])(.*)""".r val timeFormat = """\[\d\d:\d\d.\d\d\]""".r for (line ← Source.fromFile(path).getLines()) { line match { case timers(times, content) ⇒ for (time ← timeFormat.findAllIn(times)) contentList :+= Tuple2(time, content) case timer(time, content) ⇒ contentList :+= Tuple2(time, content) case title: String ⇒ titleList :+= title } } (contentList, titleList) } def expend(path: String) = { val (contentList, titleList) = inputLrc(path) titleList.foreach(println) for (x ← contentList.sorted) { println(s"${x._1}${x._2}") } } expend("lrc")}
my github
- 排序和正则表达式的应用
- 正则表达式和通配符的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式 的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- 正则表达式的应用
- json城市下拉列表
- SPOJ 196 MUSKET - Musketeers 火枪手 环类问题
- MySQl的使用笔记
- C++优先队列 合并果子
- 归并排序
- 排序和正则表达式的应用
- 快速排序
- 抽屉效果
- 冒泡排序
- HDU1078 FatMouse and Cheese [记忆化搜索DFS]
- 动态规划解回文
- 选择排序
- 查找 1
- Asp.net MVC3使用Reporting Services生成PDF解决Web在线打印