How to check to see if a string is a decimal numbe

2020-02-20 06:04发布

问题:

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?

回答1:

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.



回答2:

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


回答3:

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


回答4:

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


回答5:

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)(_ || _)
  }

}


回答6:

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


回答7:

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


回答8:

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



回答9:

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


回答10:

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
      } 


标签: scala