Scalaの正規表現ライブラリは、Javaの正規表現ライブラリのラッパーになっていて、Javaのものよりもだいぶ使いやすくはなっているが、パターンマッチに使う時は、以下のように必ずvalなどでいったん変数に代入しなければならないという欠点がある。
scala> val numPat = """[0-9]+""".r
numPat: scala.util.matching.Regex = [0-9]+
scala> "123" match { case numPat() => println("matched") }
matchedそこで、簡単な場合には、パターンにいちいち名前を付けずに済むようなライブラリをExtractorを使って書いてみた。これを使うと、たとえば上のコードは次のように書ける:
scala> ("123", """[0-9]+""") match { case Success() => println("matched") }
matched他にも、部分一致やプレフィクスに対するマッチを行うオプション、文字列から整数や浮動小数点数への変換を行うExtractorも用意してあり、以下のように書くこともできる。
scala> ("abc123", """([0-9]+)""", Part) match {
| case Success(PInt(num)) => println(num + 1)
| }
124
scala> ("1.23abc", """([0-9]+.[0-9]+)""", Pre) match {
| case Success(PFloat(num)) => println(num - 2)
| }
-0.77コードは、以下。まあ、何が言いたかったかというと、Extractorは使いようによっては結構便利なので、色々応用例を考えてみると良いのではないかということ。
object RegexPatterns {
import scala.util.matching._
object PFloat {
def unapply(s: String): Option[Float] = try {
Some(s.toFloat)
} catch { case _:NumberFormatException => None }
}
object PInt {
def unapply(s: String): Option[Int] = try {
Some(s.toInt)
} catch { case _:NumberFormatException => None }
}
abstract sealed class MatchingMode
case object Pre extends MatchingMode
case object Part extends MatchingMode
case object All extends MatchingMode
object Success {
def unapplySeq(arg: (String, String, MatchingMode)): Option[List[String]] = {
val (str, pat) = (arg._1, arg._2.r)
arg._3 match {
case Pre =>
for(matched <- pat findPrefixMatchOf str)
yield (1 to matched.groupCount) map (matched group _) toList
case Part =>
for(matched <- pat findFirstMatchIn str)
yield (1 to matched.groupCount) map (matched group _) toList
case All => pat.unapplySeq(str)
}
}
def unapplySeq(arg: (String, String)): Option[List[String]] =
unapplySeq((arg._1, arg._2, All))
}
}