gpt4 book ai didi

Scala 解析器组合器将字符列表转换为字符串

转载 作者:行者123 更新时间:2023-12-01 13:42:01 26 4
gpt4 key购买 nike

我一直在努力了解 Scala 的解析器组合器。看起来它们非常强大,但我似乎找到的唯一教程示例是数学表达式和非常少的正确的真实世界解析示例,其中包含需要解析并映射到不同实体的 DSL 等。

为了这个例子,假设我有这个 BNF,其中我有这个名为 Model 的实体,它由这样的字符串组成:[model [name <name> ]] .这是我拥有的更大 BNF 的一个简单示例,现实中有更多实体。

所以我定义了自己的类Model这需要 name作为构造函数,然后定义我自己的 ModelParser扩展 JavaTokenParsers 的对象.然后,我按照 BNF 定义了以下解析器(我知道有些解析器可能有更简单的正则表达式匹配器,但出于其他原因我更愿意完全遵循 BNF)。

def model : Parser[Model] = "[model" ~> "[name" ~> name <~ "]]" ^^ ( Model(_) )
def name : Parser[String] = (letter ~ (anyChar*)) ^^ {case text => text.toString())
def anyChar = letter | digit | "_".r | "-".r
def letter = """[a-zA-Z]""".r
def digit = """\d""".r

toStringModel看起来像这样:

override def toString : String = "[model " + name + "]"

当我尝试使用类似 [model [name helloWorld]] 的字符串运行它时我明白了 [model [h~List(e, l, l, o, W, o, r, l, d)]]而不是我期待的[model helloWorld]

如何让这些单独的字符重新加入到它们原来所在的字符串中?

我也对各个解析器和 .r 的使用感到困惑.有时我看到示例,其中只有以下内容作为解析器(解析“hello”):

def hello = "hello"

那不就是一个字符串吗?它到底是怎么突然变成一个可以与其他解析器结合的解析器的呢?什么是 .r实际上在做什么?我已经阅读了至少 3 个教程,但仍然完全不知道实际发生了什么。

最佳答案

问题是 anyChar* 解析一个 List[String](在这种情况下每个字符串都是一个字符),调用 的结果字符串列表上的 toString"List(...)",而不是通过连接内容得到的字符串。此外,case text => 模式匹配整个 letter ~ (anyChar*),而不仅仅是 anyChar* 部分。

可以非常直接地解决这两个问题:

case class Model(name: String) {
override def toString : String = "[model " + name + "]"
}

import scala.util.parsing.combinator._

object ModelParser extends RegexParsers {
def model: Parser[Model] = "[model" ~> "[name" ~> name <~ "]]" ^^ (Model(_))

def name: Parser[String] = letter ~ (anyChar*) ^^ {
case first ~ rest => (first :: rest).mkString
}

def anyChar = letter | digit | "_".r | "-".r
def letter = """[a-zA-Z]""".r
def digit = """\d""".r
}

我们只是将第一个字符串追加到其余字符串的列表中,然后对整个列表调用mkString,这将连接内容。这按预期工作:

scala> ModelParser.parseAll(ModelParser.model, "[model [name helloWorld]]")
res0: ModelParser.ParseResult[Model] = [1.26] parsed: [model helloWorld]

正如您所注意到的,让正则表达式做更多的工作是可能的(并且可能更清晰和更高效):

object ModelParser extends RegexParsers {
def model: Parser[Model] = "[model" ~> "[name" ~> name <~ "]]" ^^ (Model(_))

def name: Parser[String] = """[a-zA-Z\d_-]+""".r
}

这个例子还说明了解析组合器库使用隐式转换来减少编写解析器的一些冗长的方式。如您所说,def hello = "hello" 定义了一个字符串,而 "[a-zA-Z]+".r 定义了一个 Regex (通过 the r method on StringOps ),但都可以用作解析器,因为 RegexParsers定义从 String(这个名为 literal)和 Regex(regex)到 Parser[字符串].

关于Scala 解析器组合器将字符列表转换为字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20557480/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com