2016-05-06 1 views
1

私は実数を構文解析するために主張したプロジェクトからこれを取ったが、それは何らかの形で事前に小数部分を食べる:Parboiled - 実数を解析する方法は?

object Main extends App { 
    import org.parboiled.scala._ 

    val res = TestParser.parseDouble("2.3") 
    println(s"RESULT: ${res.result}") 

    object TestParser extends Parser { 
    def RealNumber = rule { 
     oneOrMore(Digit) ~ optional("." ~ oneOrMore(Digit)) ~> { s => 
     println(s"CAPTURED '$s'") 
     s.toDouble 
     } 
    } 
    def Digit = rule { "0" - "9" } 

    def parseDouble(input: String): ParsingResult[Double] = 
     ReportingParseRunner(RealNumber).run(input) 
    } 
} 

これが印刷されます。ここで間違っている

CAPTURED '.3' 
RESULT: Some(0.3) 

何?現在、Parboiled-1からParboiled-2に行くことはできません。なぜなら、文法を書き直す必要があるからです。

答えて

2

は、~>などのアクションルールは直前のピア規則の一致を取ります。ルールシーケンスoneOrMore(Digit) ~ optional("." ~ oneOrMore(Digit))では直前のルールはoptional("." ~ oneOrMore(Digit))であるため、アクションルールに一致するのは".3"です。

def RealNumberString = rule { 
    oneOrMore(Digit) ~ optional("." ~ oneOrMore(Digit)) 
} 

def RealNumber = rule { 
    RealNumberString ~> { s => 
    println(s"CAPTURED '$s'") 
    s.toDouble 
    } 
} 

またはスタック上に両方の部分をプッシュし、それらを組み合わせて:あなたは、例えば、別々のルールに最初の2つの要素を抽出してもよいことを修正するには

def RealNumber = rule { 
    oneOrMore(Digit) ~> identity ~ 
    optional("." ~ oneOrMore(Digit)) ~> identity ~~> { (s1, s2) => 
    val s = s1 + s2 
    println(s"CAPTURED '$s'") 
    s.toDouble 
    } 
} 
0

これは1つの解決策ですが、非常に醜いです。おそらくより良い方法があります:parboiled documentationに述べたように

def Decimal = rule { 
    Integer ~ optional[Int]("." ~ PosInteger) ~~> { (a: Int, bOpt: Option[Int]) => 
    bOpt.fold(a.toDouble)(b => s"$a.$b".toDouble) /* ??? */ 
}} 
def PosInteger = rule { Digits ~> (_.toInt) } 
def Integer  = rule { optional[Unit]("-" ~> (_ =>())) /* ??? */ ~ 
    PosInteger ~~> { (neg: Option[Unit], num: Int) => 
    if (neg.isDefined) -num else num 
    } 
} 
def Digit  = rule { "0" - "9" } 
def Digits  = rule { oneOrMore(Digit) } 

def parseDouble(input: String): ParsingResult[Double] = 
    ReportingParseRunner(Decimal).run(input) 
関連する問題