How to check to see if a string is a decimal number in Scala

Scala

Scala Problem Overview


I'm still fairly new to Scala, and I'm discovering new and interesting ways for doing things on an almost daily basis, but they're not always sensible, and sometimes already exist within the language as a construct and I just don't know about them. So, with that preamble, I'm checking to see if a given string is comprised entirely of digits, so I'm doing:

def isAllDigits(x: String) = x.map(Character.isDigit(_)).reduce(_&&_)

is this sensible or just needlessly silly? It there a better way? Is it better just to call x.toInt and catch the exception, or is that less idiomatic? Is there a performance benefit/drawback to either?

Scala Solutions


Solution 1 - Scala

Try this:

def isAllDigits(x: String) = x forall Character.isDigit

forall takes a function (in this case Character.isDigit) that takes an argument that is of the type of the elements of the collection and returns a Boolean; it returns true if the function returns true for all elements in the collection, and false otherwise.

Solution 2 - Scala

Do you want to know if the string is an integer? Then .toInt it and catch the exception. Do you instead want to know if the string is all digits? Then ask one of:

s.forall(_.isDigit)
s matches """\d+"""

Solution 3 - Scala

You also may consider something like this:

import scala.util.control.Exception.allCatch

def isLongNumber(s: String): Boolean = (allCatch opt s.toLong).isDefined
// or
def isDoubleNumber(s: String): Boolean = (allCatch opt s.toDouble).isDefined

Solution 4 - Scala

You could simply use a regex for this.

val onlyDigitsRegex = "^\\d+$".r

def isAllDigits(x: String) = x match {
  case onlyDigitsRegex() => true
  case _ => false
}

Or simply

def isAllDigits(x: String) = x.matches("^\\d+$")

And to improve this a little bit, you can use the pimp my library pattern to make it a method on your string:

implicit def AllDigits(x: String) = new { def isAllDigits = x.matches("^\\d+$") }

"12345".isAllDigits // => true
"12345foobar".isAllDigits // => false

Solution 5 - Scala

Starting Scala 2.13 we can use String::toDoubleOption, to determine whether a String is a decimal number or not:

"324.56".toDoubleOption.isDefined // true
"4.06e3".toDoubleOption.isDefined // true
"9w01.1".toDoubleOption.isDefined // false

Similar option to determine if a String is a simple Int:

"324".toIntOption.isDefined // true
"à32".toIntOption.isDefined // false
"024".toIntOption.isDefined // true

Solution 6 - Scala

import scala.util.Try


object NumCruncher {

  def isShort(aString: String): Boolean = Try(aString.toLong).isSuccess
  def isInt(aString: String): Boolean = Try(aString.toInt).isSuccess
  def isLong(aString: String): Boolean = Try(aString.toLong).isSuccess
  def isDouble(aString: String): Boolean = Try(aString.toDouble).isSuccess
  def isFloat(aString: String): Boolean = Try(aString.toFloat).isSuccess

  /**
   *
   * @param x the string to check
   * @return true if the parameter passed is a Java primitive number
   */
  def isNumber(x: String): Boolean = {
    List(isShort(x), isInt(x), isLong(x), isDouble(x), isFloat(x))
      .foldLeft(false)(_ || _)
  }

}

Solution 7 - Scala

Try might not performance-wise be the optimal choice, but otherwise it's neat:

scala> import scala.util.Try
scala> Try{ "123x".toInt }
res4: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "123x")
scala> Try{ "123x".toInt }.isSuccess
res5: Boolean = false

Solution 8 - Scala

@Jesper's answer is spot on.

Do NOT do what I'm suggesting below (explanation follows)

Since you are checking if a given string is numeric (title states you want a decimal), the assumption is that you intend to make a conversion if the forall guard passes.

A simple implicit in scope will save a whopping 9 key strokes ;-)

implicit def str2Double(x: String) = x.toDouble

Why this is dangerous

def takesDouble(x: Double) = x

The compiler will now allow takesDouble("runtime fail") since the implicit tries to convert whatever string you use to Double, with zero guarantee of success, yikes.

implicit conversions then seem better suited to situations where an acceptable default value is supplied on conversion failure (which is not always the case; therefore implicit with caution)

Solution 9 - Scala

Here is one more:

  import scala.util.Try

  val doubleConverter: (String => Try[Double]) = (s: String) => Try{ s.map(c => if ((Character.isDigit(c) == true) || (c == '.')) Some(c) else None).flatten.mkString.toDouble }

  val d1: Try[Double] = doubleConverter("+ 1234.0%")
  val d2: Try[Double] = doubleConverter("+ 1234..0%")

Solution 10 - Scala

Based on brilliant Jexter's solution, in this piece of code I take care of the NullPointerException using Option:

    def isValidPositiveNumber(baseString: Option[String]): Boolean = baseString match {
        case Some(code) => !code.isEmpty && (code forall Character.isDigit)
        case None => false
      } 

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
QuestionPlexQView Question on Stackoverflow
Solution 1 - ScalaJesperView Answer on Stackoverflow
Solution 2 - ScalaRex KerrView Answer on Stackoverflow
Solution 3 - ScalaTvarohView Answer on Stackoverflow
Solution 4 - ScaladrexinView Answer on Stackoverflow
Solution 5 - ScalaXavier GuihotView Answer on Stackoverflow
Solution 6 - ScalaYordan GeorgievView Answer on Stackoverflow
Solution 7 - ScalaakauppiView Answer on Stackoverflow
Solution 8 - ScalavirtualeyesView Answer on Stackoverflow
Solution 9 - ScalaajmnskView Answer on Stackoverflow
Solution 10 - ScalaJavier BañezView Answer on Stackoverflow