Suppose that I have a string in scala and I want to try to parse a double out of it.
I know that, I can just call toDouble
and then catch the java num
Scala 2.13
introduced String::toDoubleOption:
"5.7".toDoubleOption // Option[Double] = Some(5.7)
"abc".toDoubleOption // Option[Double] = None
"abc".toDoubleOption.getOrElse(-1d) // Double = -1.0
There's nothing like this not only in Scala, but even in basic Java.
Here's a piece code that does it without exceptions, though:
def parseDouble(s: String)(implicit nf: NumberFormat) = {
val pp = new ParsePosition(0)
val d = nf.parse(s, pp)
if (pp.getErrorIndex == -1) Some(d.doubleValue) else None
}
Usage:
implicit val formatter = NumberFormat.getInstance(Locale.ENGLISH)
Console println parseDouble("184.33")
Console println parseDouble("hello, world")
Scalaz provides an extension method parseDouble
on String
s, which gives a value of type Validation[NumberFormatException, Double]
.
scala> "34.5".parseDouble
res34: scalaz.Validation[NumberFormatException,Double] = Success(34.5)
scala> "34.bad".parseDouble
res35: scalaz.Validation[NumberFormatException,Double] = Failure(java.lang.NumberFormatException: For input string: "34.bad")
You can convert it to Option
if so required.
scala> "34.bad".parseDouble.toOption
res36: Option[Double] = None
You could try using util.control.Exception.catching
which returns an Either
type.
So using the following returns a Left wrapping a NumberFormatException
or a Right wrapping a Double
import util.control.Exception._
catching(classOf[NumberFormatException]) either "12.W3".toDouble
I'd usually go with an "in place" Try:
def strTimesTen (s: String) = for (d <- Try(s.toDouble)) yield d * 10
strTimesTen("0.1") match {
Success(d) => println( s"It is $d" )
Failure(ex) => println( "I've asked for a number!" )
}
Note, that you can do further calculation in the for and any exception would project into a Failure(ex). AFAIK this is the idiomatic way of handling a sequence of unreliable operations.
For Scala 2.13+ see Xavier's answer below. Apparently there's a toDoubleOption
method now.
For older versions:
def parseDouble(s: String) = try { Some(s.toDouble) } catch { case _ => None }
Fancy version (edit: don't do this except for amusement value; I was a callow youth years ago when I used to write such monstrosities):
case class ParseOp[T](op: String => T)
implicit val popDouble = ParseOp[Double](_.toDouble)
implicit val popInt = ParseOp[Int](_.toInt)
// etc.
def parse[T: ParseOp](s: String) = try { Some(implicitly[ParseOp[T]].op(s)) }
catch {case _ => None}
scala> parse[Double]("1.23")
res13: Option[Double] = Some(1.23)
scala> parse[Int]("1.23")
res14: Option[Int] = None
scala> parse[Int]("1")
res15: Option[Int] = Some(1)