2

パーサーコンビネーターを使用してテキストファイルを解析しようとしています。というクラスでインデックスとテキストをキャプチャしたいと思いますExample。入力ファイルのフォームを示すテストは次のとおりです。

object Test extends ParsComb with App {
  val input = """
0)
blah1
blah2
blah3
1)
blah4
blah5
END
"""
  println(parseAll(examples, input))
}

そして、これがうまくいかない私の試みです:

import scala.util.parsing.combinator.RegexParsers

case class Example(index: Int, text: String)

class ParsComb extends RegexParsers {
  def examples: Parser[List[Example]] = rep(divider~example) ^^ 
                                          {_ map {case d ~ e => Example(d,e)}}
  def divider:  Parser[Int]           = "[0-9]+".r <~ ")"    ^^ (_.toInt)
  def example:  Parser[String]        = ".*".r <~ (divider | "END") 
}

それは失敗します:

[4.1] failure: `END' expected but `b' found

blah2

^

私はこれらから始めたばかりなので、私が何をしているのかあまりわかりません。".*".r問題は、正規表現が複数行を実行していないことにあると思います。正しく解析されるようにこれを変更するにはどうすればよいですか?

4

3 に答える 3

5
  • エラーメッセージはどういう意味ですか?

文法の定義によれば".*".r <~ (divider | "END")、、はパーサーに、exampleadividerまたは。のいずれかを続ける必要があることを伝えましたEND。blah1を解析した後、パーサーは検索dividerに失敗し、次に試行しEND、再度失敗しました。他に利用できるオプションがないため、これENDが本番値の最後の選択肢でした。パーサーの観点からは、予想されENDていましたが、すぐに見つかった、次の入力はblah24行目からでした。

  • それを修正する方法は?

実装に近づけるようにしてください。あなたの場合の文法は次のようになります。

examples ::= {divider example}
divider  ::= Integer")"
example  ::= {literal ["END"]}

「例」を解析List[String]する方が理にかなっていると思います。とにかく、それはあなた次第です。

問題はexampleパーサーです。繰り返し可能なリテラルである必要があります。

それで 、

class ParsComb extends RegexParsers {
  def examples: Parser[List[Example]] = rep(divider ~ example) ^^ { _ map { case d ~ e => Example(d, e) } }
  def divider: Parser[Int] = "[0-9]+".r <~ ")" ^^ (_.toInt)
  def example: Parser[List[String]] = rep("[\\w]*(?=[\\r\\n])".r <~ opt("END"))
}

正規表現は、それが前向きな先読みであり、または(?=[\\r\\n])が後に続く文字と一致することを意味します。\r\n

解析結果は次のとおりです。

[10.1]解析済み:List(Example(0、List(blah1、blah2、blah3))、Example(1、List(blah4、blah5)))

(ではなく)文字列に解析する場合は、次List[String]のような変換関数を追加するだけです。^^ {_ mkString "\n"}

于 2012-06-20T10:46:07.550 に答える
2

パーサーは改行文字を処理できません。exampleパーサーはnextdividerを削除し、example正規表現が一致dividerして「END」文字列になります。

これを試して:

object ParsComb extends RegexParsers { 
  def examples: Parser[List[Example]] = rep(divider~example) <~ """END\n?""".r ^^ {_ map {case d ~ e => Example(d,e)}} 
  def divider: Parser[Int] = "[0-9]+".r <~ ")\n" ^^ (_.toInt) 
  def example: Parser[String] = rep(str) ^^ {_.mkString}
  def str: Parser[String] = """.*\n""".r ^? { case s if simpleLine(s) => s}

  val div = """[0-9]+\)\n""".r
  def simpleLine(s: String) = s match {
    case div() => false
    case "END\n" => false
    case _ => true
  }

  def apply(s: String) = parseAll(examples, s)
}

結果:

scala> ParsComb(input)
res3: ParsComb.ParseResult[List[Example]] =
[10.1] parsed: List(Example(0,blah1
blah2
blah3
), Example(1,blah4
blah5
))
于 2012-06-20T06:18:08.967 に答える
1

問題は、「。*」。r正規表現が複数行を実行していないことにあると思います。

その通り。dotall修飾子(奇妙なことに「s」と呼ばれます)を使用します。

def example:  Parser[String]        = "(?s).*".r <~ (divider | "END") 
于 2012-06-20T17:07:45.940 に答える