How to find if a Scala String is parseable as a Double or not?

Scala

Scala Problem Overview


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 format exception if this fails, but is there a cleaner way to do this? For example if there was a parseDouble function that returned Option[Double] this would qualify.

I don't want to put this in my own code if it already exists in the standard library and I am just looking for it in the wrong place.

Thanks for any help you can provide.

Scala Solutions


Solution 1 - Scala

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)

Solution 2 - Scala

Scalaz provides an extension method parseDouble on Strings, 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

Solution 3 - Scala

scala> import scala.util.Try
import scala.util.Try

scala> def parseDouble(s: String): Option[Double] = Try { s.toDouble }.toOption
parseDouble: (s: String)Option[Double]

scala> parseDouble("3.14")
res0: Option[Double] = Some(3.14)

scala> parseDouble("hello")
res1: Option[Double] = None

Solution 4 - Scala

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

Solution 5 - Scala

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

Solution 6 - Scala

Unfortunately, this isn't in the standard library. Here's what I use:

class SafeParsePrimitive(s: String) {
  private def nfe[T](t: => T) = {
    try { Some(t) }
    catch { case nfe: NumberFormatException => None }
  }
  def booleanOption = s.toLowerCase match {
    case "yes" | "true" => Some(true)
    case "no" | "false" => Some(false)
    case _ => None
  }
  def byteOption = nfe(s.toByte)
  def doubleOption = nfe(s.toDouble)
  def floatOption = nfe(s.toFloat)
  def hexOption = nfe(java.lang.Integer.valueOf(s,16))
  def hexLongOption = nfe(java.lang.Long.valueOf(s,16))
  def intOption = nfe(s.toInt)
  def longOption = nfe(s.toLong)
  def shortOption = nfe(s.toShort)
}
implicit def string_parses_safely(s: String) = new SafeParsePrimitive(s)

Solution 7 - Scala

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

Solution 8 - Scala

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionchuck taylorView Question on Stackoverflow
Solution 1 - ScalaLuigi PlingeView Answer on Stackoverflow
Solution 2 - ScalamissingfaktorView Answer on Stackoverflow
Solution 3 - ScalaJeff SchwabView Answer on Stackoverflow
Solution 4 - ScalaDon MackenzieView Answer on Stackoverflow
Solution 5 - ScalaXavier GuihotView Answer on Stackoverflow
Solution 6 - ScalaRex KerrView Answer on Stackoverflow
Solution 7 - ScalaFixpointView Answer on Stackoverflow
Solution 8 - ScalaMavView Answer on Stackoverflow