使用 Scala 组合器解析创建对象实例
Creating an instance of an object using Scala combinator parsing
我有这个解析器:
import scala.util.parsing.combinator.JavaTokenParsers
class RequestMappingParser extends JavaTokenParsers {
def requestMapping: Parser[Any] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")"
def commaDelimitedSeq: Parser[Any] = repsep(keyValue, ",")
def keyValue: Parser[Any] = key ~ "=" ~ value
def key: Parser[Any] = "value" | "method"
def value: Parser[Any] = """[^)]*""".r
}
我有这个简单的 class:
class MethodRequestMapping(val value: String, val method: String)
我的解析器可以解析这个字符串:
"@RequestMapping(value = \"/ex/foos\", method = RequestMethod.GET)"
和 return 是 Parser[Any]
的结果。我希望 return 是 Parser[MethodRequestMapping]
.
的结果
我该怎么做?我知道我必须做这样的事情:
def requestMapping: Parser[MethodRequestMapping] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")" ^^ {
// Some sort of pattern matching and creation of MethodRequestMapping
// ???
}
但 ????还是换一种完全不同的方式更好?
首先,您使用的一半组合被创建为 Parser[String]
,并且是您的类型注释将它们向上转换为 Parser[Any]
(由于协方差,这是允许的,但在这种情况)。
所以你实际上有这样的东西:
class RequestMappingParser extends JavaTokenParsers {
def requestMapping: Parser[String ~ List[String ~ String ~ String] ~ String] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")"
def commaDelimitedSeq: Parser[List[String ~ String ~ String]] = repsep(keyValue, ",")
def keyValue: Parser[String ~ String ~ String] = key ~ "=" ~ value
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^)]*""".r
}
然后我们可以使用 map
或 ^^
来调整类型 - 之前它很困难,因为我们在那里有 Any
,但如果我们不摆脱类型,我们将能够轻松进行模式匹配
class RequestMappingParser extends JavaTokenParsers {
// result of this parser will be ethier "value" or "method"
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^),]*""".r // you had an error here, you were missing "," to separate items
// here we'll map String ~ String ~ String to tuple - we'll drop unused "=" in the process
def keyValue: Parser[(String, String)] = (key ~ "=" ~ value).map {
case k ~ _ ~ v => k -> v
}
// repsep wil return List[(String, String)], which we'll map to Map
def commaDelimitedSeq: Parser[Map[String, String]] = repsep(keyValue, ",").map(_.toMap)
// this would give us String ~ Map[String, String] ~ String, but we don't need
// these String constants. Also we can map things into out final result
def requestMapping: Parser[MethodRequestMapping] = ("@RequestMapping(" ~ commaDelimitedSeq ~ ")").map {
case _ ~ map ~ _ =>
new MethodRequestMapping(value = map("value"), method = map("method"))
}
}
val parser = new RequestMappingParser()
val parsed = "@RequestMapping(value = \"/ex/foos\", method = RequestMethod.GET)"
val result = parser.parse(parser.requestMapping, parsed).get
// result.value == "\"/ex/foos\""
// result.method == "RequestMethod.GET"
就是说 - 不鼓励使用此解析器组合库,主要是因为它很慢。对于生产,建议使用类似 FastParse 的东西,它具有更快的实施速度和更多的功能。
我有这个解析器:
import scala.util.parsing.combinator.JavaTokenParsers
class RequestMappingParser extends JavaTokenParsers {
def requestMapping: Parser[Any] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")"
def commaDelimitedSeq: Parser[Any] = repsep(keyValue, ",")
def keyValue: Parser[Any] = key ~ "=" ~ value
def key: Parser[Any] = "value" | "method"
def value: Parser[Any] = """[^)]*""".r
}
我有这个简单的 class:
class MethodRequestMapping(val value: String, val method: String)
我的解析器可以解析这个字符串:
"@RequestMapping(value = \"/ex/foos\", method = RequestMethod.GET)"
和 return 是 Parser[Any]
的结果。我希望 return 是 Parser[MethodRequestMapping]
.
我该怎么做?我知道我必须做这样的事情:
def requestMapping: Parser[MethodRequestMapping] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")" ^^ {
// Some sort of pattern matching and creation of MethodRequestMapping
// ???
}
但 ????还是换一种完全不同的方式更好?
首先,您使用的一半组合被创建为 Parser[String]
,并且是您的类型注释将它们向上转换为 Parser[Any]
(由于协方差,这是允许的,但在这种情况)。
所以你实际上有这样的东西:
class RequestMappingParser extends JavaTokenParsers {
def requestMapping: Parser[String ~ List[String ~ String ~ String] ~ String] = "@RequestMapping(" ~ commaDelimitedSeq ~ ")"
def commaDelimitedSeq: Parser[List[String ~ String ~ String]] = repsep(keyValue, ",")
def keyValue: Parser[String ~ String ~ String] = key ~ "=" ~ value
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^)]*""".r
}
然后我们可以使用 map
或 ^^
来调整类型 - 之前它很困难,因为我们在那里有 Any
,但如果我们不摆脱类型,我们将能够轻松进行模式匹配
class RequestMappingParser extends JavaTokenParsers {
// result of this parser will be ethier "value" or "method"
def key: Parser[String] = "value" | "method"
def value: Parser[String] = """[^),]*""".r // you had an error here, you were missing "," to separate items
// here we'll map String ~ String ~ String to tuple - we'll drop unused "=" in the process
def keyValue: Parser[(String, String)] = (key ~ "=" ~ value).map {
case k ~ _ ~ v => k -> v
}
// repsep wil return List[(String, String)], which we'll map to Map
def commaDelimitedSeq: Parser[Map[String, String]] = repsep(keyValue, ",").map(_.toMap)
// this would give us String ~ Map[String, String] ~ String, but we don't need
// these String constants. Also we can map things into out final result
def requestMapping: Parser[MethodRequestMapping] = ("@RequestMapping(" ~ commaDelimitedSeq ~ ")").map {
case _ ~ map ~ _ =>
new MethodRequestMapping(value = map("value"), method = map("method"))
}
}
val parser = new RequestMappingParser()
val parsed = "@RequestMapping(value = \"/ex/foos\", method = RequestMethod.GET)"
val result = parser.parse(parser.requestMapping, parsed).get
// result.value == "\"/ex/foos\""
// result.method == "RequestMethod.GET"
就是说 - 不鼓励使用此解析器组合库,主要是因为它很慢。对于生产,建议使用类似 FastParse 的东西,它具有更快的实施速度和更多的功能。