W.P. McNeill
W.P. McNeill

Reputation: 17026

How to test if Scala combinator parser matches a string

I have a Scala combinator parser that handles comma-delimited lists of decimal numbers.

object NumberListParser extends RegexParsers {
  def number: Parser[Double] = """\d+(\.\d*)?""".r ^^ (_.toDouble)

  def numbers: Parser[List[Double]] = rep1sep(number, ",")

  def itMatches(s: String): Boolean = parseAll(numbers, s) match {
    case _: Success[_] => true
    case _ => false
  }
}

The itMatches function returns true when given a string that matches the pattern. For example:

NumberListParser.itMatches("12.4,3.141") // returns true
NumberListParser.itMatches("bogus") // returns false

Is there a more terse way to do this? I couldn't find one in the documentation, but my function sees a bit verbose, so I wonder if I'm overlooking something.

Upvotes: 1

Views: 1109

Answers (3)

Travis Brown
Travis Brown

Reputation: 139038

I guess I should add my comment as an answer, since it is the answer. You can use the successful method on ParseResult, which is designed for precisely this purpose:

import scala.util.parsing.combinator._

object NumberListParser extends RegexParsers {
  def number = """\d+(\.\d*)?""".r ^^ (_.toDouble)
  def numbers = rep1sep(number, ",")

  def itMatches(s: String): Boolean = parseAll(numbers, s).successful
}

This gives exactly the same behavior as your implementation.

Upvotes: 3

senia
senia

Reputation: 38045

You can define itMatches as so:

def itMatches(s: String): Boolean = parseAll(numbers, s).map{ r => true }.getOrElse(false)

You don't need parser. Regex is enough:

var R = """\d+(\.\d*)?(,\d+(\.\d*)?)*""".r
def itMatches(s: String) = s match {
  case R(_*) => true
  case _ => false
}

scala> itMatches("12.4,3.141")
res0: Boolean = true

scala> itMatches("bogus")
res1: Boolean = false

Upvotes: 1

Guillaume Massé
Guillaume Massé

Reputation: 8064

You could use JavaTokenParsers and benefit from decimalNumbers

object NumberListParser extends JavaTokenParsers {
  def number: Parser[Double] = decimalNumbers ^^ (_.toDouble)
  def numbers: Parser[List[Double]] = rep1sep(number, ",")
  def itMatches(s: String): Boolean = parseAll(numbers, s) match {
    case _: Success[_] => true
    case _ => false
  }
}

Upvotes: 3

Related Questions