scala MatchError 从模式匹配创建元组

scala MatchError in creating tuple from Pattern Matching

我写了下面的代码:

case class Filters(city: List[String], isType: List[String])

val input = "BNG:school | HYD:school,restaurant"

val(filter1:Filters, filter2:Filters) = input.split("\|") match {
  case Array(f1, f2) => (f1.split(":") match {
      case Array(c,t) => t match {
        case _ if t contains "," => Filters(List(c.trim), t.split(",").map(_.trim).toList)
        case _ => Filters(List(c.trim), List(t.trim))
      }
    },
    f2.split(":") match {
      case Array(c,t) => t match {
        case _ if t contains "," => Filters(List(c.trim), t.split(",").map(_.trim).toList)
        case _ => Filters(List(c.trim), List(t.trim))
    }
  })
  case _ => (input.split(":") match {
    case Array(x,y) => Filters(List(x.trim), List(y.trim))
  },Nil)
}

它给出以下输出:

filter1: Filters = Filters(List(BNG),List(school))
filter2: Filters = Filters(List(HYD),List(school, restaurant))

但是如果我将输入更改为:val input = "BNG:school"

输出给出错误:

Exception in thread "main" scala.MatchError: (Filters(List(BNG),List(school)),List()) (of class scala.Tuple2)

我不知道我做错了什么? 我有三种类型的输入:

BNG:school
HYD:school,restaurant
BNG:school | HYD:school,restaurant

代码应该适用于这些类型的输入。

其次: 如果我从 filter1 和 filter2 中删除数据类型 Filters 它给出的输出为:

filter1: Filters = Filters(List(BNG),List(school))
filter2: Product with Serializable = Filters(List(HYD),List(school, restaurant))

为什么 filter1Filters 类型而 filter2 Serializable 类型的产品?

感谢任何帮助。

提前致谢。

正如评论者所说,这是因为您在等式的左侧有一个元组。

也许下面的内容更好?

case class Filters(city: List[String], isType: List[String])

val regex = "(\w+):([,\w]+)".r
val input = "BNG:school | HYD:school,restaurant"

val result = input.split("\|").map(regex.findFirstMatchIn).map {
  case Some(m) => Filters(List(m.group(1)), m.group(2).split(",").toList)
  case None => throw new Exception("No match")
}

println(result) // Array(Filters(List("BNG"), List("school")), Filters(List("HYD"), List("school", "restaurant")))

在匹配块中使用 if-guards 时,还要注意 2.12 上的 https://github.com/scala/bug/issues/5365

您的代码假设 input 包含 2 个 Filter 字符串。如果它实际上包含少于 2 或多于 2,那么事情就会崩溃。

这可以通过以多种方式多次拆分输入来完成。

val input = "BNG:school | HYD:school,restaurant|LND,HKG:restaurant"
input.split("\s*\|\s*")
  .map { ss =>
    val Array(cs, ts) = ss.split("\s*:\s*")
    Filters(cs.split(",").toList, ts.split(",").toList)
  }.toList

//res0 = List(Filters(List(BNG),List(school))
//          , Filters(List(HYD),List(school, restaurant))
//          , Filters(List(LND, HKG),List(restaurant)))

或者您可以使用正则表达式模式来帮助隔离数据元素。

val re = "([^|:]+):([^|:]+)".r
re.findAllMatchIn(input)
  .map(m => Filters(m.group(1).trim.split(",").toList
                   ,m.group(2).trim.split(",").toList)).toList

这里的一大优势是正则表达式搜索将简单地跳过格式错误的数据(例如丢失的 :)而不是抛出错误。


regex 模式解释:

  • [^|:] - 任何 not 的字符(^ 表示 not)一个小节 | 或冒号 :
  • [^|:]+ - 必须至少是其中的 1 个(+ 表示 1-or-more
  • ([^|:]+) - 记住那个组(parens 创建一个“捕获组”)
  • ([^|:]+):([^|:]+) - 2 个捕获组(group(1)group(2))由冒号 : 分隔。每组由冒号前后的所有字符组成,这些字符不是条形码或冒号字符。