2015-11-02 82 views
2

我一直在撞牆,試圖找出如何讓這個工作。最初的解析器工作得很好,但是當我試圖從中得到一個Map時,它只給出了初始數值,但不是他重視塊。Scala Combinator解析器映射問題

格式爲 「浮動:[標籤浮動:[optinallabel浮動:] ...]」,如:

 412285.556: [Label 0.0:[Label1 1.0:][Label2 2.0:] 

的解析器列表:

object ParseList extends JavaTokenParsers { 
    def sep : Parser[String] = ":" 
    def string : Parser[Any] = """[\.a-zA-Z0-9]+""".r 
    def num: Parser[Any] = floatingPointNumber <~ sep 
    def valueBlock: Parser[Any] = "["~>rep(valueBlock)<~"]" | string ~ floatingPointNumber <~ sep 
    def expr: Parser[Any] = num ~ rep(valueBlock) 
    def apply(in: String) = parseAll(expr,in) 
} 

測試給:

scala> ParseList("""412285.556: """) 
res150: ParseList.ParseResult[Any] = [1.13] parsed: (412285.556~List()) 

scala> ParseList("""412285.556: [Label 1.0:]""") 
res151: ParseList.ParseResult[Any] = [1.25] parsed: (412285.556~List(List((Label~1.0)))) 

scala> ParseList("""412285.556: [Label 0.0:[Label1 1.0:][Label2 2.0:]]""") 
res152: ParseList.ParseResult[Any] = [1.51] parsed: (412285.556~List(List((Label~0.0), List((Label1~1.0)), List((Label2~2.0))))) 

當我嘗試使它成爲一個Map,如果只返回數字,但調用成員例程。看到調試輸出。

地圖分析器:

object ParseMap extends JavaTokenParsers { 
    // Seperator 
    def sep : Parser[String] = ":" 
    // string 
    def string : Parser[String] = """[a-zA-Z][a-zA-Z0-9]+""".r 
    // Block within [] with label value: and option additional blocks 
    def valueBlock: Parser[(String,Any)] = 
     member <~ rep(obj) 
    // Member - value pair within a block 
    def member: Parser[(String, Any)] = 
    string ~ floatingPointNumber <~ sep ^^ 
     { case s ~ n => (s, n); println("In Member s=" +s+" n="+n); (s, n)} 
    def obj: Parser[Map[String,Any]] = 
    "["~> rep(valueBlock) <~"]" ^^ {Map() ++ _} 
    // Initial number value of the data 
    def num: Parser[(String, Any)] = 
      floatingPointNumber <~ sep ~ rep(obj) ^^ 
      { case floatingPointNumber => ("Num", floatingPointNumber) } 
    // order of operations 
    def value: Parser[Any] = (
     num 
     | obj 
     | member 
     | floatingPointNumber 
     | string 
    ) 
    def apply(in: String) = parseAll(value,in) 
} 

測試得出:

scala> ParseMap("""412285.556: """) 
res154: ParseMap.ParseResult[Any] = [1.13] parsed: (Num,412285.556) 

scala> ParseMap("""412285.556: [Label 1.0:]""") 
In Member s=Label n=1.0 
res155: ParseMap.ParseResult[Any] = [1.25] parsed: (Num,412285.556) 

scala> ParseMap("""412285.556: [Label 0.0:[Label1 1.0:][Label2 2.0:]]""") 
In Member s=Label n=0.0 
In Member s=Label1 n=1.0 
In Member s=Label2 n=2.0 
res156: ParseMap.ParseResult[Any] = [1.51] parsed: (Num,412285.556) 

我所有的嘗試得到一個單一的地圖出來,已經失敗。任何幫助將不勝感激。

回答

2

的主要問題是您在num方法<~組合子的使用 - 這個扔掉所有解析數據跟隨它的(包括你想爲你的地圖rep(obj)解析結果)。行修改爲類似:

def num: Parser[(String, Any)] = 
     floatingPointNumber ~ sep ~ rep(obj) ^^ 
     { case floatingPointNumber ~ sep ~ objs => ("Num", (floatingPointNumber, objs)) } 

和你開始像結果:

scala> ParseMap("""412285.556: [Label 0.0:[Label1 1.0:][Label2 2.0:]]""") 
In Member s=Label n=0.0 
In Member s=Label1 n=1.0 
In Member s=Label2 n=2.0 
res3: ParseMap2.ParseResult[Any] = [1.51] parsed: (Num,(412285.556,List(Map(Label -> 0.0)))) 

,雖然它可能看起來並不很喜歡你可能會想什麼,應該給你一個起點指向進一步發展。

+0

我認爲這將在本猛衝得到我。 – user190941

2

Scala的解析器組合器不是最容易使用的東西,而且它們非常慢。改爲嘗試fastparse

我不能完全弄清楚你想從這些數據中得到什麼(這是一個非常奇怪的格式!),但有一個很好的guide to getting started

核心標籤解釋可能會看起來像

val Pair = P(Label ~ " " ~ Num ~ ":") 
val MapLine = P("[" Pair ~ ("[" ~ Pair ~ "]").rep ~ "]"). 
    map{ case (pair, pairs) => pair :: pairs.toList } 
+0

謝謝,一旦我明白了這一點,我就打算看看快速分類。 – user190941