trick parser dynamic delimiter eludes me

31 views
Skip to first unread message

Razvan Cojocaru

unread,
Jun 1, 2012, 2:11:43 PM6/1/12
to scala-user

I am trying to write a parser for a delimited content, which content specifies the delimiting character, i.e.:

 

{{delimited;:Name,heading1,heading2}}

1;2;3;4

{{/delimited}}

 

So I got this to match the start and extract the delimiter

 

  def csvStart: Parser[CsvHeading] = "{{delimited" ~> """.""".r ~ ":".r ~ """[^:]*""".r ~ opt(":".r ~ csvHeadings) <~ "}}" ^^ {

    case delim ~ _ ~ what ~ Some(head) =>  …

 

Now – having the delimiter – how do I use it to build the NEXT parsers? Here’s the overall parser – don’t know how to make it dynamic:

 

  def csvContent: PS = csvStart ~ csv(";") ~ csvEnd ^^ {

 

note the csv(“;”) which builds the content parser for the given delimiter… I need something that looks back at the result of the previous parser (csvStart) and extracts the delimiter from that result…

 

what to do? what to do? (insert hair pulling frowney).

 

Thanks,

Razie

Daniel Sobral

unread,
Jun 1, 2012, 5:48:40 PM6/1/12
to Razvan Cojocaru, scala-user
See "into" (also ">>").
--
Daniel C. Sobral

I travel to the future all the time.

Razvan Cojocaru

unread,
Jun 1, 2012, 7:42:04 PM6/1/12
to Daniel Sobral, scala-user
NICE - thank you.

... a little cumbersome, since it discards the first result, so I had to
modify the second signature to carry it over as a tuple... not good 'cause
it couples my second parser with the first, but [T] to the rescue :)

Before:

def csv(implicit xdelim:String): Parser[List[List[String]]] = csvLines ^^
{ case x => (c,x) }

After:

def csv[T](c:T)(implicit xdelim:String): Parser[(T,List[List[String]])] =
csvLines ^^ { case x => (c,x) }

oh well - beats parsing the thing twice, which was my hack.

Thanks,
Razie

Daniel Sobral

unread,
Jun 1, 2012, 9:11:23 PM6/1/12
to Razvan Cojocaru, scala-user
On Fri, Jun 1, 2012 at 8:42 PM, Razvan Cojocaru <p...@razie.com> wrote:
> NICE - thank you.
>
> ... a little cumbersome, since it discards the first result, so I had to
> modify the second signature to carry it over as a tuple... not good 'cause
> it couples my second parser with the first, but [T] to the rescue :)
>
> Before:
>
>  def csv(implicit xdelim:String): Parser[List[List[String]]] = csvLines ^^
> { case x => (c,x) }
>
> After:
>
>  def csv[T](c:T)(implicit xdelim:String): Parser[(T,List[List[String]])] =
> csvLines ^^ { case x => (c,x) }
>
> oh well - beats parsing the thing twice, which was my hack.

You haven't seen the light yet. ^^ is map, >> is flatMap. Consider,
for instance, p and q equivalents below:

def p = a ~ b ~ c
def q = for {
x <- a
y <- b
z <- c
} yield ~(x, ~(y, c)

So you don't really need to change the second parser. You can do it like this:

for {
delim <- Start
body <- Body
_ <- End(delim)
} yield body

Which converts back to:

Start >> { delim => Body >> { body => End(delim) ^^ { case _ => body } } }

Or, a bit more shortly,

Start >> { delim => Body <~ End(delim) }

Anyway, you should have gotten the drift now. I don't actually use for
comprehensions with parsers (though I submitted a patch to get filter
working with it :), but I find it useful to figure out composition of
parsers.

Razvan Cojocaru

unread,
Jun 1, 2012, 11:12:05 PM6/1/12
to scala-user
Most enlightening, thank you. I figured >> was flatmap but using ^^ ... I
got used to copy paste it around as a piece of accessory syntax there...
thanks for the wake up!

This is what I have now

Old
def wikiPropCsv: PS = "{{delimited:" ~> (wikiPropCsvStart >> {h:CsvHeading
=> csv(h)(h.delim) }) <~ "{{/delimited}}" ^^ { new
def wikiPropCsv: PS = "{{delimited:" ~> (wikiPropCsvStart >> {h:CsvHeading
=> csv(h.delim) ^^ {x => (h,x)}}) <~ "{{/delimited}}" ^^ {

cheers,
Reply all
Reply to author
Forward
0 new messages