给定字符串格式的结构化数据如何使用模式匹配和正则表达式有效地提取部分数据?
示例:
val input = Seq("name-12345","inval1d-12345","invalid-12here123","hello-54321","inval1d-1aa2")
case class Client(name:Option[String],clientID:Option[Int])
def parseClient(input:String):Option[Client] = {
val clientRegex = """([a-zA-Z]+)-([0-9]+)""".r
Option(input).flatMap(in => {
in match {
case clientRegex(name,clientID) => Some(Client(Some(name),Some(clientID.toInt)))
case _ => None
}
})
}
input.map(parseClient)
然而,问题是,如果我无法验证结构化数据的单个部分,那么我解析它没有。
我如何使用正则表达式在分层庄园中定义,例如:
val nameRegex = """([a-zA-Z]+)""".r
val clientIDRegex = """([0-9]+)""".r
然后将这些组合在一个模式中?
示例的输出:
Seq(
Some(Client(Some("name"),Some(12345)))
,None
,None
,Some(Client(Some("hello"),Some(54321)))
,None
)
所需的输出:
Seq(
Some(Client(Some("name"),Some(12345)))
,Some(Client(None,Some(12345)))
,Some(Client(Some("invalid"),None))
,Some(Client(Some("hello"),Some(54321)))
,None
)
答案 0 :(得分:2)
这应该给出预期的结果:
val input = Seq("name-12345", "inval1d-12345", "invalid-12here123", "hello-54321")
case class Client(name: Option[String], clientID: Option[Int])
def parseClient(input: String): Option[Client] = {
val clientRegex = """(?:([a-zA-Z^-]+)|[^-]*)-(?:([0-9]+)|.*)""".r
input match {
case clientRegex(null, null) => None
case clientRegex(name, id) => Some(Client(Option(name), Option(id).map(_.toInt)))
case _ =>
None
}
}
input.map(parseClient)
我删除了flatMap构造,因为这是不必要的。 这里有趣的部分是正则表达式:
"""(?:([a-zA-Z^-]+)|[^-]*)-(?:([0-9]+)|.*)"""
我做了更改,因此它需要正确的值,因此会在组中捕获它(([a-zA-Z^-]+)
表示名称,([0-9]+)
表示id),但也添加了其他情况(没有有效的名称或ID )。一切都在非捕获组(?:)中,因此它被正确分组。
如果捕获组中的某些内容不符合预期,则该组将为null,这将在匹配大小写中处理。
EDIT 对代码进行了更正,以使其适用于完全无效的输入并删除不必要的if语句
编辑2 根据OP的评论改编代码,利用Option(null)=>无评估
答案 1 :(得分:0)
您可能正在寻找可以链接的应用程序。
你可以使用猫的Validated
类型做这样的事情:
val houseNumber = parseClient("house_number").andThen{ n =>
if (isValid(n)) Validated.valid(n)
else Validated.invalid(ParseError("house_number"))
}
和
我会选择使用atto:
它具有ParseResult
类型,保留解析字符串的所有信息。