Tuesday, October 20, 2015

Notes for Programming in Scala 2nd Edition (part 3)

Extractors

Email

object Example1 {
  object Email extends ((String, String) => String) {
    override def apply(v1: String, v2: String): String = {
      v1 + "@" + v2
    }
    def unapply(str: String): Option[(String, String)] = {
      val parts: Array[String] = str split "@"
      if(parts.length == 2) Some(parts(0), parts(1)) else None
    }
  }
}

Repeated string

object Example1 {
  object Twice extends ((String) => String) {
    override def apply(v1: String): String = {
      v1 + v1
    }
    def unapply(s: String): Option[String] = {
      val length = s.length / 2
      val firstHalf = s.substring(0, length)
      val secondHalf = s.substring(length)
      if(firstHalf == secondHalf) Some(firstHalf) else None
    }
  }

  def isRepeated(s: String): Unit = {
    s match {
      case Twice(y) => println(y + " repeated!")
      case _ => println("Not repeated")
    }
  }

  isRepeated("abcd")
  isRepeated("abab")
}

UpperCase

object Example1 {
  object UpperCase {
    def unapply(s: String): Boolean = s.toUpperCase == s
  }

  "ABC" match {
    case UpperCase() => println("Upper case!")
    case _ => 
  }
}

Nested pattern matching

object Example {
  object Email extends ((String, String) => String) {
    override def apply(v1: String, v2: String): String = {
      v1 + "@" + v2
    }
    def unapply(str: String): Option[(String, String)] = {
      val parts: Array[String] = str split "@"
      if(parts.length == 2) Some(parts(0), parts(1)) else None
    }
  }

  object Twice extends ((String) => String) {
    override def apply(v1: String): String = {
      v1 + v1
    }
    def unapply(s: String): Option[String] = {
      val length = s.length / 2
      val firstHalf = s.substring(0, length)
      val secondHalf = s.substring(length)
      if(firstHalf == secondHalf) Some(firstHalf) else None
    }
  }
  object UpperCase {
    def unapply(s: String): Boolean = s.toUpperCase == s
  }

  def userIsTwiceUpper(s: String) = s match {
    case Email(Twice(x @ UpperCase()), domain) => {
      println(x + " is a match!")
    }
    case _ => println("No match!")
  }

  userIsTwiceUpper("abab@g.com")
  userIsTwiceUpper("abAB@g.com")
  userIsTwiceUpper("ABAB@g.com") // match
}

Variable argument extractors (unapplySeq)

object Example {

  object Email extends ((String, String) => String) {
    override def apply(v1: String, v2: String): String = {
      v1 + "@" + v2
    }

    def unapply(str: String): Option[(String, String)] = {
      val parts: Array[String] = str split "@"
      if (parts.length == 2) Some(parts(0), parts(1)) else None
    }
  }

  object Domain {
    def apply(parts: String*): String = {
      parts.reverse.mkString(".")
    }

    def unapplySeq(whole: String): Option[Seq[String]] = {
      Some(whole.split("\\.").reverse)
    }
  }

  def isTomAtDotCom(s: String): Boolean = s match {
    case Email("tom", Domain("com", _*)) => true
    case _ => false
  }

  isTomAtDotCom("tom@g.org")
  isTomAtDotCom("tom@g.com")
}

Fixed part + variable part

object Example1 {
  object ExpandedEmail {
    def unapplySeq(email: String): Option[(String, List[String])] = {
      val parts = email.split("@")
      if(parts.length == 2) {
        Some(parts(0), parts(1).split("\\.").reverse.toList)
      } else {
        None
      }
    }
  }

  val s = "tom@support.epfl.ch"
  // use @ in pattern matching
  // and : in varargs function
  val ExpandedEmail(name, topdom, subdoms @ _*) = s
}

Regex

object Example1 {
  val decimal = """(-)?(\d+)(\.\d*)?""".r
  decimal.findFirstIn("0.15, 2.14, 5, 25, -123.24, -5, -56.24")
  val it = decimal.findAllIn("0.15, 2.14, 5, 25, -123.24, -5, -56.24")
  it.foreach(println(_))

  // split string with regex
  "a\tb c  d".split("""\s+""")

  // extract groups with regex
  val decimal(sign, integerPart, decimalPart) = "-1.245"
  val decimal(sign1, integerPart1, decimalPart1) = "1.245" // sign1 is null here

  // mix extractors with regex searches
  for(decimal(s, i, d) <- decimal.findAllIn("1.2, 3.4, -5.1")) {
    println("sign: %s, int: %s, dec: %s".format(s, i, d))
  }
}

0 comments: