在Scala中查找匹配行的惯用方法

Bil*_*ill 3 scala

我有一个Iterable[String]代表文件中的行,我想找到该序列中与正则表达式匹配的第一行,并返回由正则表达式提取的数值.文件足够大,将整个内容加载到内存然后调用toString()或其他东西是没有意义的,所以我需要一次一行.

这是我的(它有效):

val RateRegex : Regex = ".....".r

def getRate(source : Source) : Option[Double] = {
  import java.lang.Double._

  for(line <- source.getLines() ) {
    line match {
      case RateRegex(rawRate) => return Some(parseDouble(rawRate))
      case None => ()
    }
  }

  return None
}
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎很难看.感觉非常迫切,并且case None => ()可能会被评论说"你做错了".

我想我想要类似于def findFirstWhereNonNone(p : Function[A,Option[B]]) => Option[B]集合元素的类型A.

是否有内置方法可以让我以更实用的方式执行此操作?我应该写那个方法吗?

PS虽然我在使用它,是否有替代使用java.lang.Double.parseDouble?Scala的Double课不公开它.

PPS我在SO上看过很多帖子,建议SourceAPI不应该用于生产,但它们都是从2008年和2009年开始的.那还是这样吗?如果是这样,我应该为IO使用什么?

更新

我现在有:

import util.matching.Regex.Groups

for{line <- source.getLines()
    Groups(rawRate) <- RateRegex.findFirstMatchIn(line)} {
  return Some(parseDouble(rawRate))
}

return None
Run Code Online (Sandbox Code Playgroud)

对我来说感觉好多了.

The*_*aul 5

编辑:这第三个替代方案非常简洁:

source
.getLines()
.collectFirst{ case RateRegex(x) => x.toDouble}
Run Code Online (Sandbox Code Playgroud)

不确定它是否更具功能性,但您可以在Options上使用foreach/for-comprehensions的行为

def getRate(source : Source) : Option[Double] = {

     for {line    <- source.getLines() 
          rawRate <- RateRegex.findFirstIn(line)}
       return  Some(rawRate toDouble)

  return None
}
Run Code Online (Sandbox Code Playgroud)

这也有效(与EasyAngel的答案非常相似):

source
.getLines()
.map{RateRegex.findFirstMatchIn(_)}
.filter{_.isDefined}
.map{_.get.group(0).toDouble}
.head
.toList
.headOption
Run Code Online (Sandbox Code Playgroud)

最后三个有点难看.take(1)是为了确保我们只评估第一场比赛.toList用于强制进行求值,headOption用于提取第一个值为Some()或None(如果没有).有没有更惯用的方法呢?