构造函数中的Scala Regex模式匹配实例化子类

时间:2012-11-19 17:37:48

标签: regex scala pattern-matching immutability

我有以下代码来进行正则表达式模式匹配。

class UserAgent(val ua: String) {
  val iOS = """.*(iPad|iPhone|iPod).*OS ([0-9_]+).*""".r
  val Android = """.*Android ([0-9.]+).*""".r
  val WindowsPhone = """.*Windows Phone OS.*""".r
  val WebOS = """.*webOS.*""".r
  val BlackBerry = """.*BlackBerry.*""".r
  val WAPBrowser = """.*(MIDP|UP\.Browser|Obigo|Polaris|BREW|Brew|NetFront).*""".r

  var platform = "UnknownPlatform"
  var platformVersion = "UnknownVersion"

  ua match {
    case iOS(_, version) => {
      platform = "IOS"
      platformVersion = version.replace("_", ".")
    }
    case Android(version) => {
      platform = "Android"
      platformVersion = version
    }
    case WindowsPhone() => platform = "WindowsPhone"
    case WebOS() => platform = "WebOS"
    case BlackBerry() => platform = "BlackBerry"
    case WAPBrowser(p) => platform = "WAPBrowser"
  }
}

可以使用(简化)代码进行测试:

val tests = for (
    str <- List("Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7",
      "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
      "bla bla Windows Phone OS bla bla",
      "bla bla webOS bla bla",
      "bla bla BlackBerry bla bla",
      "LG-LX600 Polaris/6.0 MMP/2.0 Profile/MIDP-2.1 Configuration/CLDC-1.1")
  ) yield new UserAgent(str)

tests foreach { ua => println(ua.platform + " " + ua.platformVersion) }

由于我的班级UserAgent具有可变变量platformplatformVersion,因此这不太可靠。我想要实现的是具有不变性,因此要定义trait定义platformplatformVersion以及将返回不同值的子类。我缺少的是如何创建一个构造函数,它将实例化并返回这样的子类。

2 个答案:

答案 0 :(得分:4)

您可以使用Tuple2

  val (platform, platformVersionOpt) = ua match {
    case iOS(_, version) => "IOS" -> Some(version.replace("_", "."))
    case Android(version) => "Android" -> Some(version)
    case WindowsPhone() => "WindowsPhone" -> None
    case WebOS() => "WebOS" -> None
    case BlackBerry() => "BlackBerry" -> None
    case WAPBrowser(p) => "WAPBrowser" -> None
  }

  val platformVersion = platformVersionOpt.getOrElse("UnknownPlatform")

Scala方法是使用unapply方法创建对象:

object UserAgent {
  val iOS = """.*(iPad|iPhone|iPod).*OS ([0-9_]+).*""".r
  val Android = """.*Android ([0-9.]+).*""".r
  val WindowsPhone = """.*Windows Phone OS.*""".r
  val WebOS = """.*webOS.*""".r
  val BlackBerry = """.*BlackBerry.*""".r
  val WAPBrowser = """.*(MIDP|UP\.Browser|Obigo|Polaris|BREW|Brew|NetFront).*""".r

  def unapply(ua: String): Option[(String, Option[String])] = ua match {
      case iOS(_, version) => Some("IOS" -> Some(version.replace("_", ".")))
      case Android(version) => Some("Android" -> Some(version))
      case WindowsPhone() => Some("WindowsPhone" -> None)
      case WebOS() => Some("WebOS" -> None)
      case BlackBerry() => Some("BlackBerry" -> None)
      case WAPBrowser(p) => Some("WAPBrowser" -> None)
      case _ => None
    }
}

用法:

scala> val tests = List("Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7", "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Nexus One Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "bla bla Windows Phone OS bla bla", "bla bla webOS bla bla", "bla bla BlackBerry bla bla", "LG-LX600 Polaris/6.0 MMP/2.0 Profile/MIDP-2.1 Configuration/CLDC-1.1")

scala> tests foreach {
     |   case UserAgent(p, v) => println(p + " " + v.getOrElse("UnknownVersion"))
     |   case _ => println("UnknownPlatform UnknownVersion")
     | }
IOS 4.0
Android 2.2
WindowsPhone UnknownVersion
WebOS UnknownVersion
BlackBerry UnknownVersion
WAPBrowser UnknownVersion

答案 1 :(得分:1)

一个可能的答案,使用Tuple2Option[String]作为版本。 我还将正则表达式移动到了伴侣对象。

object UserAgent {
  val iOS = """.*(iPad|iPhone|iPod).*OS ([0-9_]+).*""".r
  val Android = """.*Android ([0-9.]+).*""".r
  val WindowsPhone = """.*Windows Phone OS.*""".r
  val WebOS = """.*webOS.*""".r
  val BlackBerry = """.*BlackBerry.*""".r
  val WAPBrowser = """.*(MIDP|UP\.Browser|Obigo|Polaris|BREW|Brew|NetFront).*""".r
}

class UserAgent(val ua: String) {
  import UserAgent._

  val (platform, version): (String, Option[String]) = ua match {
    case iOS(_, version) =>
      ("IOS", Some(version.replace("_", ".")))
    case Android(version) =>
      ("Android", Some(version))
    case WindowsPhone() => 
      ("WindowsPhone", None)
    case WebOS() => 
      ("WebOS", None)
    case BlackBerry() => 
      ("BlackBerry", None)
    case WAPBrowser(p) => 
      ("WAPBrowser", None)
  }
}