【问题标题】:Scala parsing, how to go through what has been collectedScala解析,如何通过已收集的内容
【发布时间】:2015-07-21 02:24:12
【问题描述】:

使用scala parser combinators 我已经解析了一些文本输入,并在此过程中创建了一些我自己的类型。结果打印正常。现在我需要检查输出,我认为它是一个包含我创建的类型的嵌套结构。我该怎么办?
这就是我调用解析器的方式:

GMParser1.parseItem(i_inputHard_2) match {
  case GMParser1.Success(res, _) =>
    println(">" + res + "< of type: " + res.getClass.getSimpleName)
  case x => 
    println("Could not parse the input string:" + x)
} 

编辑 我从MsgResponse(O2 Flow|Off) 得到的是:

>(MsgResponse~(O2 Flow~Off))< of type: $tilde

而我从WthrResponse(Id(Tube 25,Carbon Monoxide)|0.20) 得到的回复是:

>(WthrResponse~IdWithValue(Id(Tube 25,Carbon Monoxide),0.20))< of type: $tilde

这里只是为问题提供上下文是一些输入解析。我想联系Id:

trait Keeper
case class Id(leftContents:String,rightContents:String) extends Keeper

这里是 Id 正在创建:

def id = "Id(" ~> idContents <~ ")"  ^^ { contents => Id(contents._1,contents._2) } 

这是整个解析器:

object GMParser1 extends RegexParsers {
  override def skipWhitespace = false
  def number = regex(new Regex("[-+]?(\\d*[.])?\\d+"))
  def idContents = text ~ ("," ~> text)
  def id = "Id(" ~> idContents <~ ")"  ^^ { contents => Id(contents._1,contents._2) }
  def text = """[A-Za-z0-9* ]+""".r
  def wholeWord = """[A-Za-z]+""".r
  def idBracketContents = id ~ ( "|" ~> number ) ^^ { contents => IdWithValue(contents._1,contents._2) }
  def nonIdBracketContents = text ~ ( "|" ~> text )
  def bracketContents = idBracketContents | nonIdBracketContents
  def outerBrackets = "(" ~> bracketContents <~ ")"
  def target = wholeWord ~ outerBrackets
  def parseItem(str: String): ParseResult[Any] = parse(target, str)

  trait Keeper
  case class Id(leftContents:String,rightContents:String) extends Keeper
  case class IdWithValue(leftContents:Id,numberContents:String) extends Keeper
}

【问题讨论】:

  • 结果似乎不包含任何Ids,因此似乎没有什么可获取的。也许id 规则从未被调用(或者它从未在给定的输入上成功)或者你在任何规则调用id 中丢弃了它的结果。
  • 我在想,当映射 (^^) 完成时,Id 将被放入输出中。我只是把整个解析器放好,以防你能看到我丢弃的地方。我可以解决这个问题,它甚至可能是最好的方法(但是??功能不如需要使用var),方法是在创建Id 等时存储它们。
  • 您的意见是什么?看起来它根本不匹配idBracketContents 规则,而是进入nonIdBracketContents 规则。
  • 我的错误。你是对的,输入非常简单。我将更改文本以显示两个输入和相应的输出。但我的问题是为了更笼统。我如何获取 $tilde 的所有内容,包括我创建的内容以及其他可能包含大量 ParserResult[T] 或类似内容的内容...
  • 仅供参考:在 Scala 中,该类称为 ~,而不是 $tilde。它只是在这里打印为$tilde,因为您使用的是Java 反射,而~ 在Java 中不是有效名称(与Scala 不同)。

标签: scala parsing


【解决方案1】:

~ 运算符创建的解析器生成 ~ 案例类的值。要获取它的内容,您可以像在任何其他案例类上一样对其进行模式匹配(请记住,它的名称是象征性的,因此使用中缀)。

因此,您可以将case GMParser1.Success(res, _) =&gt; ... 替换为case GMParser1.Success(functionName ~ argument) =&gt; ... 以获取函数名称和参数(或wholeWord "(" bracketContents ")"wholeWordbracketContents 的任何语义)。然后,您可以类似地使用嵌套模式来获取参数的各个部分。

您也可以(并且可能应该)在规则中使用^^ 和模式匹配来创建不包含~ 的更有意义的AST 结构。例如,这将有助于区分 nonIdBracketContents 结果和 bracketContents 结果。

【讨论】:

  • 暂时,或者直到我变得更加纯粹的功能我将继续我的想法,即保存Id或任何原位。我已经完成了模式匹配,为什么还要再做一次? (那么为什么我首先问你可能会说!)。最好知道一个很好的例子/参考来正确处理输出。到目前为止,我看到的大多数文档都只关注解析。
  • @ChrisMurphy 创建自己的数据类型而不是 ~ 的好处是您可以区分 nonIdBracketContentsbracketContents 而无需更深入地查看内部是否有任何 @ 987654336@s 在那里与否。而在更复杂的语法中,如果只使用~,可能会出现根本无法区分不同规则的结果的情况。至于“正确”处理输出,这完全取决于你想用它做什么。
  • 输出是指第一个词法分析阶段的输出。 ~ 真的包含整个解析树吗?人们是否通常会查看 ~ 内部或做我所做的事情(现在实际上是使用 FastParse),并且只需将地图功能放在旁边即可创建您想要看到的内容。
  • @ChrisMurphy 是的,我想到了,但你想用它做什么?你想评价一下吗?从中生成代码?从中生成某种形式的 IR?在任何一种情况下:你的语言的语义是什么? “~真的包含整个解析树吗?”它包含~ 的两个操作数的结果。您使用~&gt;&lt;~ 忽略的任何内容都不会包含在内。也不会有任何信息告诉您选择了| 的哪一侧。 “人们通常 [...] 吗?”人们通常使用^^ 来创建适当的 AST,然后从那里使用它。
  • 我有一些对象需要使用 Autowire 和 uPickle 通过 http(不知何故涉及 Ajax)发送/接收。我正在确定字符串表示,但从字符串 -> 对象开始变得复杂,所以我选择使用解析器。有一些方法可以更多地使用 uPickle,但最后我尝试了这种方法。所以我已经在做人们通常做的事情了!
猜你喜欢
  • 1970-01-01
  • 2010-12-06
  • 2012-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-01
  • 2019-07-25
  • 1970-01-01
相关资源
最近更新 更多