在 Scala 中解析 SemVer
Parsing SemVer in Scala
我正在尝试使用解析器组合器在 Scala 中编写 SemVer (http://semver.org) 解析器,以熟悉它们。
这是我当前的代码:
case class SemVer(major: Int, minor: Int, patch: Int, prerelease: Option[List[String]], metadata: Option[List[String]]) {
override def toString = s"$major.$minor.$patch" + prerelease.map("-" + _.mkString(".")).getOrElse("") + metadata.map("+" + _.mkString("."))
}
class VersionParser extends RegexParsers {
def number: Parser[Int] = """(0|[1-9]\d*)""".r ^^ (_.toInt)
def separator: Parser[String] = """\.""".r
def prereleaseSeparator: Parser[String] = """-""".r
def metadataSeparator: Parser[String] = """\+""".r
def identifier: Parser[String] = """([0-9A-Za-z-])+""".r ^^ (_.toString)
def prereleaseIdentifiers: Parser[List[String]] = (number | identifier) ~ rep(separator ~> (number | identifier)) ^^ {
case first ~ rest => List(first.toString) ++ rest.map(_.toString)
}
def metadataIdentifiers: Parser[List[String]] = identifier ~ rep(separator ~> identifier) ^^ {
case first ~ rest => List(first.toString) ++ rest.map(_.toString)
}
}
我想知道我应该如何解析预发布部分的标识符,因为它不允许在数字标识符中使用前导零,并且当我尝试使用我当前的解析器前导零(例如在“01.2.3”中)进行解析时) 简单地成为一个包含元素 0.
的列表
更一般地说,我应该如何检测字符串不符合 SemVer 规范并因此强制出现故障条件?
经过一番尝试和搜索,我发现问题是我调用了 parse
方法而不是 parseAll
方法。由于 parse
基本上尽可能多地解析,当它不能再解析时结束,它有可能接受部分正确的字符串。使用 parseAll
强制解析所有输入,如果解析停止后还有剩余输入,则它将失败。这正是我要找的。
为了完整起见,我要添加
def version = number ~ (separator ~> number) ~ (separator ~> number) ~ ((prereleaseSeparator ~> prereleaseIdentifiers)?) ~ ((metadataSeparator ~> metadataIdentifiers)?) ^^ {
case major ~ minor ~ patch ~ prerelease ~ metadata => SemVer(major, minor, patch, prerelease, metadata)
}
方法 VersionParser
我正在尝试使用解析器组合器在 Scala 中编写 SemVer (http://semver.org) 解析器,以熟悉它们。
这是我当前的代码:
case class SemVer(major: Int, minor: Int, patch: Int, prerelease: Option[List[String]], metadata: Option[List[String]]) {
override def toString = s"$major.$minor.$patch" + prerelease.map("-" + _.mkString(".")).getOrElse("") + metadata.map("+" + _.mkString("."))
}
class VersionParser extends RegexParsers {
def number: Parser[Int] = """(0|[1-9]\d*)""".r ^^ (_.toInt)
def separator: Parser[String] = """\.""".r
def prereleaseSeparator: Parser[String] = """-""".r
def metadataSeparator: Parser[String] = """\+""".r
def identifier: Parser[String] = """([0-9A-Za-z-])+""".r ^^ (_.toString)
def prereleaseIdentifiers: Parser[List[String]] = (number | identifier) ~ rep(separator ~> (number | identifier)) ^^ {
case first ~ rest => List(first.toString) ++ rest.map(_.toString)
}
def metadataIdentifiers: Parser[List[String]] = identifier ~ rep(separator ~> identifier) ^^ {
case first ~ rest => List(first.toString) ++ rest.map(_.toString)
}
}
我想知道我应该如何解析预发布部分的标识符,因为它不允许在数字标识符中使用前导零,并且当我尝试使用我当前的解析器前导零(例如在“01.2.3”中)进行解析时) 简单地成为一个包含元素 0.
的列表更一般地说,我应该如何检测字符串不符合 SemVer 规范并因此强制出现故障条件?
经过一番尝试和搜索,我发现问题是我调用了 parse
方法而不是 parseAll
方法。由于 parse
基本上尽可能多地解析,当它不能再解析时结束,它有可能接受部分正确的字符串。使用 parseAll
强制解析所有输入,如果解析停止后还有剩余输入,则它将失败。这正是我要找的。
为了完整起见,我要添加
def version = number ~ (separator ~> number) ~ (separator ~> number) ~ ((prereleaseSeparator ~> prereleaseIdentifiers)?) ~ ((metadataSeparator ~> metadataIdentifiers)?) ^^ {
case major ~ minor ~ patch ~ prerelease ~ metadata => SemVer(major, minor, patch, prerelease, metadata)
}
方法 VersionParser