字符串模式匹配最佳实践

时间:2011-10-08 18:19:59

标签: scala pattern-matching

以下代码不起作用,但它描述了我想要做的事情。

你能否推荐一个解决这个问题的最佳方法?

def resolveDriver(url: String) = {
  url match {
    case url.startsWith("jdbc:mysql:") => "com.mysql.jdbc.Driver"
    case url.startsWith("jdbc:postgresql:") => "org.postgresql.Driver"
    case url.startsWith("jdbc:h2:") => "org.h2.Driver"
    case url.startsWith("jdbc:hsqldb:") => "org.hsqldb.jdbcDriver"
    case _ => throw new IllegalArgumentException
  }
}

4 个答案:

答案 0 :(得分:42)

就语法而言,你只需修改一下case case语句:

case url if url.startsWith("jdbc:mysql:") => "com.mysql.jdbc.Driver"

这只是将值url绑定到模式表达式(也是url)并添加带有测试的保护表达式。这应该使代码编译。

为了使它更像scala,你可以返回一个Option [String](我删除了一个子句,因为它只是为了说明):

def resolveDriver(url: String) = url match {
  case u if u.startsWith("jdbc:mysql:") => Some("com.mysql.jdbc.Driver")
  case u if u.startsWith("jdbc:postgresql:") => Some("org.postgresql.Driver")
  case _ => None
}

除非您想管理异常,否则

答案 1 :(得分:10)

这是另一种方式。将所有映射存储在地图中,然后使用collectFirst方法查找匹配项。 collectFirst的类型签名是:

def TraversableOnce[A].collectFirst[B](pf: PartialFunction[A, B]): Option[B]

用法:

scala> val urlMappings = Map("jdbc:mysql:" -> "com.mysql.jdbc.Driver", "jdbc:postgresql:" -> "org.postgresql.Driver")
urlMappings: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(jdbc:mysql: -> com.mysql.jdbc.Drive
r, jdbc:postgresql: -> org.postgresql.Driver)

scala> val url = "jdbc:mysql:somestuff"
url: java.lang.String = jdbc:mysql:somestuff

scala> urlMappings collectFirst { case(k, v) if url startsWith k => v }
res1: Option[java.lang.String] = Some(com.mysql.jdbc.Driver)

答案 2 :(得分:1)

Scala 2.13开始,可以按unapplying a string interpolator模式匹配String s:

val s"jdbc:$dialect:$rest" = "jdbc:mysql:whatever"
// dialect: String = "mysql"
// rest: String = "whatever"

然后在我们的例子中,只需使用Map将提取的值(sql方言)映射到适当的驱动程序即可:

val drivers = Map(
  "postgresql" -> "org.postgresql.Driver",
  "mysql"      -> "com.mysql.jdbc.Driver",
  "h2"         -> "org.h2.Driver"
)
val driver = drivers(dialect)
// driver: String = "com.mysql.jdbc.Driver"

如果您期望输入格式错误,还可以使用match语句:

"jdbc:postgresql:something" match {
  case s"jdbc:$dialect:$rest" => Some(dialect)
  case _                      => None
}
// Option[String] = Some("postgresql")

答案 3 :(得分:0)

import PartialFunction._  // condOpt

val drivers = Map( 
  "mysql" -> "mysql driver",
  "h2" -> "h2 driver" 
  // ... 
)
val pattern = "^jdbc:(\\w+):.*".r

def resolveDriver(url: String) = condOpt(url) { 
  case pattern(dbms) => drivers.get(dbms) 
}.flatten.getOrElse(throw new IllegalArgumentException)