问题描述
我写了以下代码:
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,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),restaurant))
为什么 filter1 是 Filters 类型,而 filter2 是具有可序列化的产品类型?
感谢您的帮助。
谢谢。
解决方法
您的代码假定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(",m.group(2).trim.split(",").toList)).toList
此处的一大优势是,正则表达式搜索将仅跳过格式不正确的数据(例如丢失的:
),而不会引发错误。
正则表达式模式说明:
-
[^|:]
-不是(^
表示 not )的任何字符,竖杠|
或冒号{{1 }} -
:
-必须至少是其中的1个([^|:]+
表示 1或更多) -
+
-记住该组(父母创建了一个“捕获组”) -
([^|:]+)
-2个捕获组(([^|:]+):([^|:]+)
和group(1)
)之间用冒号group(2)
隔开。每个组均由冒号前后的所有字符组成,这些字符不是长条或冒号字符。
正如评论者所说,这是因为您在等式的左侧有一个元组。
也许以下几点更好?
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。