在Scala中解析语义化版本号(SemVer)

3
我正在尝试使用解析器组合器在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 规范,并因此强制失败条件?

2个回答

1

在一番试验和搜索后,我发现问题出在我调用了parse方法而不是parseAll方法。由于parse方法基本上会尽可能多地解析,直到无法继续解析为止,因此它有可能接受部分正确的字符串。使用parseAll方法强制解析所有输入,并在解析停止时仍有剩余输入时失败。这正是我要找的。


0

为了完整起见,我会添加

def version = number ~ (separator ~> number) ~ (separator ~> number) ~ ((prereleaseSeparator ~> prereleaseIdentifiers)?) ~ ((metadataSeparator ~> metadataIdentifiers)?) ^^ {
  case major ~ minor ~ patch ~ prerelease ~ metadata => SemVer(major, minor, patch, prerelease, metadata)
}

方法到 VersionParser


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接