在Scala中解析字符串然后转换为另一种格式

时间:2017-02-20 08:52:36

标签: scala parsing parser-combinators

我有一个命题公式,例如,用这种字符串格式:

(~d \/ x) /\ (y \/ ~b) /\ (~y \/ a \/ b)

我写了一个像这样的解析器:

import scala.util.parsing.combinator._

class CNFParser extends JavaTokenParsers with RegexParsers {
  def expr: Parser[Any] = term~rep("/\\"~term)
  def term: Parser[Any] = value~rep("\\/"~value)
  def value: Parser[Any] =  ident | "~"~ident | "("~expr~")"

}

object Test_02 extends CNFParser {
  def main(args: Array[String]): Unit = {

    println("input: " + "(~d \\/ x) /\\ (y \\/ ~b) /\\ (~y \\/ a \\/ b)")
    println(parseAll(expr, "(~d \\/ x) /\\ (y \\/ ~b) /\\ (~y \\/ a \\/ b)"))

  }
}

好吧,解析后的输出如下:

[1.41] parsed: (((((~(((~~d)~List((\/~x)))~List()))~))~List())~List((/\~((((~((y~List((\/~(~~b))))~List()))~))~List())), (/\~((((~(((~~y)~List((\/~a), (\/~b)))~List()))~))~List()))))

我正在通过使用操作^^尝试多种方法来摆脱这些“额外”的括号和内容,但没有成功。

实际上,我想得到的结果是以.dimacs格式转换公式,其中每个字母/单词都是数字,\/运算符变为space之间的\/文字和newline变为0(在每行的末尾插入值x = 1, y = 2, a = 3, b = 4, d = 5)。具体来说,对于我的示例 - 如果c filename.cnf p cnf 5 3 -5 1 0 2 -4 0 -2 3 4 - 那么生成的文件必须如下所示:

.gitattributes

任何提示如何继续实现这一点真的很受欢迎!感谢。

1 个答案:

答案 0 :(得分:1)

你不想拥有Parser[Any];相反,定义表示公式的数据类型:

sealed trait Formula
case class Variable(name: String) extends Formula {
  override def toString = name
}
case class And(left: Formula, right: Formula) {
  override def toString = s"($left /\ $right)"
}
// etc.

您也可以将最终需要的任何操作添加到Formula(或同伴对象)。

然后定义Parser[Formula]并使用Formula s,而不是使用字符串。

Formula是代数数据类型的示例,通过搜索此术语,您可以找到更多信息。