2

I have been beating my head against a wall, trying to figure out how to get this to work. The initial parser worked great, but when I try to get a Map out of it, it is only giving the initial number value, but not he value blocks.

The format is "float: [label float: [optinallabel float:] ...]" like:

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

The parser to list is:

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)
}

Testing gives:

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)))))

When I try to make it a Map, if only returns the number, but calls the member routine. See the debug output.

The Map parser:

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)
}

The testing gives:

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)

All my attempts to get a single Map out of it, has failed. Any help would be greatly appreciated.

0

2 Answers 2

3

Scala's parser combinators are not the easiest thing to use, and they're extraordinarily slow. Try fastparse instead.

I can't quite figure out what you want from that data (it's a very strange format!), but there's a nice guide to getting started.

Your core label-interpreter will probably look something like

val Pair = P(Label ~ " " ~ Num ~ ":")
val MapLine = P("[" Pair ~ ("[" ~ Pair ~ "]").rep ~ "]").
  map{ case (pair, pairs) => pair :: pairs.toList }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I was planning on looking at fastparse, once I figured this out.
2

The main problem is your use of the <~ combinator in the num method - this throws away all parsed data that follows it (including the rep(obj) parse result that you want for your map). Modify that line to something like:

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

and you start getting results like:

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))))

which, while it probably doesn't look quite like what you might be wanting, should give you a starting point to progress further.

1 Comment

I think this will get me by this hurtle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.