我正在尝试从标记化的String中提取值,并从中创建一个(可选的)case类实例。
String采用以下形式:
val text = "name=John&surname=Smith"
我有一个Person类,它接受这两个值:
case class Person(name: String, surname: String)
我有一些代码可以进行转换:
def findKeyValue(values: Array[String])(prefix: String): Option[String] =
values.find(_.startsWith(prefix)).map(_.substring(prefix.length))
val fields: Array[String] = text.split("&")
val personOp = for {
name <- findKeyValue(fields)("name=")
surname <- findKeyValue(fields)("surname=")
} yield Person(name, surname)
虽然这产生了我需要的答案但我想知道:
一些限制:
文本中名称和姓氏字段的顺序可以更改。以下内容也有效:
val text = "surname=Smith&name=John"
可能还有其他字段需要忽略:
val text = "surname=Smith&name=John&age=25"
解决方案需要满足提供的文本格式错误或没有必填字段的时间。
解决方案无法使用反射或宏。
答案 0 :(得分:2)
如果你在开始时将它一直解析为Map[String,String]
(而不是Array[String]
,那么它会更有效率。
如果您碰巧将apache的http-client库作为依赖项的一部分(如果您使用的是Web框架,那么很有可能),我会使用它:
import org.apache.http.client.utils.URLEncodedUtils
import java.nio.charset.StandardCharsets
import scala.collection.JavaConverters._
val values = URLEncodedUtils.parse(text, StandardCharsets.UTF_8)
.asScala.map(x => x.getName -> x.getValue).toMap
val personOpt =
for {
name <- values.get("name")
surname <- values.get("surname")
} yield Person(name, surname)
使用库的原因是假设这是来自各种类型的http请求,您很可能需要对键以及库所处理的值或其他详细信息进行urldecode。
我认为提取器版本会过度,但这就是它的样子:
object PersonFromString {
def unapply (s: String): Option[Person] = { ... same as above ... }
}
...
text match {
case PersonFromString(person) => ... do something with it...
...
}
答案 1 :(得分:0)
我想说,做这些事情的更惯用的方法是使用Extractors
。
考虑这个答案:Read case class object from string in Scala (something like Haskell's "read" typeclass)
答案 2 :(得分:0)
在解析字符串时,从属性到值构造Map[String,Option[String]]
,例如
val m = text.split("&")
.map(_.split("="))
.filter(_.size == 2)
.map (xs => xs.head -> Some(xs.last))
.toMap
获取例如
Map(surname -> Some(Smith), name -> Some(John))
要获取构造类实例的值(例如,已经提供的提取器),请像这样使用getOrElse
m.getOrElse("kjkj",None)
Option[String] = None
m.getOrElse("surname",None)
Option[String] = Some(Smith)
案例类需要重新制定为
case class Person(name: Option[String], surname: Option[String])
每当字符串不包含name
中不存在的此类属性/值时,surname
和None
可能为Map
。另请注意,为了传达大小为2的数组的过滤,可以使用模式匹配。