我想扫描一个文件,只找到正则表达式的第一个实例,然后返回与表达式匹配的组的值。
到目前为止,我所有的尝试似乎都非常笨拙,并且涉及到反复使用正则表达式,一次找到目标字符串,然后再次获得组。我也不喜欢在Regexp的开头和结尾使用。*。
有谁能提出一个更优雅的方法吗?
val DateRegexp = """.*(dddd)-(dd)-(dd).*""".r
val lineWithDate = scala.io.Source.fromFile(filenameGC).getLines().find{_.matches(""".*(dddd)-(dd)-(dd).*""") }
lineWithDate match {
case Some(result) =>
result match {
case DateRegexp(year, month, day) =>
println(year, month, day)
}
case None =>
println("No date found in file")
}
经过Cyrille Corpet的大力投入,我现在有…
val DateRegexp = """(dddd)-(dd)-(dd)""".r.unanchored
scala.io.Source.fromFile(filenameGC).getLines().collectFirst{
case DateRegexp(y, m, d) => println(y, m, d)}
Regex
已经是一个模式(在模式匹配的意义上),所以您可以直接在case
语句中使用它:
fileString match {
case DateRegexp(year, month, day) => println(year, month, day)
}
但是,在您的示例中,.*
是贪婪的,它将捕获字符串中模式的最后一次出现。
值得庆幸的是,您可以在模式的开始和结束处删除.*
,如果您将其指定为unanchored
(意味着它不会尝试将模式与您的整个字符串匹配)。没有贪心的*
,现在可以捕获第一个出现:
val regex = """(dddd)-(dd)-(dd)""".r.unanchored
"1987-05-18 2002-12-14" match {
case regex(y, m, d) => (y.toInt, m.toInt, d.toInt) // (1987, 5, 18)
}
编辑:我意识到我没有解决问题的第一个问题,那就是你没有String
,而是Seq[String]
。然而,一旦您有了一行的提取器,您只需要在所有行上使用它,直到第一个与collectFirst
相关的行,它会找到第一个与给定的case
匹配的事件,并对它做一些事情:
(lines: List[String]).collectFirst{
case regex(y, m, d) => println(y, m, d)
}