web-dev-qa-db-fra.com

Comment vérifier si une chaîne est un nombre décimal dans Scala

Je suis encore relativement nouveau à Scala et je découvre de nouvelles façons de faire les choses presque tous les jours, mais elles ne sont pas toujours judicieuses et existent parfois dans la langue en tant que construction et je n'en t savoir à leur sujet. Donc, avec ce préambule, je vérifie si une chaîne donnée est entièrement composée de chiffres, alors je fais:

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

est-ce raisonnable ou juste inutilement stupide? Y a-t-il une meilleure façon? Est-il préférable d'appeler x.toInt et d'attraper l'exception, ou est-ce moins idiomatique? Existe-t-il un avantage/inconvénient lié aux performances?

47
PlexQ

Essaye ça:

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

forall prend une fonction (dans ce cas, Character.isDigit) qui prend un argument du type des éléments de la collection et retourne une Boolean; elle retourne true si la fonction renvoie true pour tous les éléments de la collection, et false sinon.

82
Jesper

Voulez-vous savoir si la chaîne est un entier? Puis .toInt et attrapez l'exception. Voulez-vous plutôt savoir si la chaîne est composée uniquement de chiffres? Puis demandez à l'un des:

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

Vous pouvez également envisager quelque chose comme ceci:

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
22
Tvaroh

Vous pouvez simplement utiliser une regex pour cela.

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

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

Ou simplement

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

Et pour améliorer cela un peu, vous pouvez utiliser le modèle pimp my library pour en faire une méthode sur votre chaîne:

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

"12345".isAllDigits // => true
"12345foobar".isAllDigits // => false
5
drexin
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)(_ || _)
  }

}
4
Yordan Georgiev

Try n'est peut-être pas le choix optimal en termes de performances, mais sinon, c'est bien:

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
2
akauppi

@ La réponse de Jesper est parfaite.

DoNOTfais ce que je suggère ci-dessous (l'explication suit)

Puisque vous vérifiez si une chaîne donnée est numérique (le titre indique que vous voulez une décimale), l’hypothèse est que vous avez l’intention de faire une conversion si la garde forall passe.

Une simple portée implicite permettra d'économiser 9 frappes clés ;-)

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

Pourquoi c'est dangereux  

def takesDouble(x: Double) = x

Le compilateur va maintenant autoriser takesDouble("runtime fail") puisque l’implicite essaie de convertir la chaîne que vous utilisez en Double, avec aucune garantie de succès, yikes.

les conversions implicites semblent alors mieux adaptées aux situations dans lesquelles une valeur par défaut acceptable est fournie en cas d'échec de la conversion (ce qui n'est pas toujours le cas; donc implicite avec prudence).

1
virtualeyes

En voici un de plus:

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

Sur la base de la solution géniale de Jexter, dans ce morceau de code, je m'occupe de l'exception NullPointerException en utilisant Option:

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

À partir de Scala 2.13, nous pouvons utiliser String::toDoubleOption pour déterminer si une chaîne est un nombre décimal ou non:

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

Option similaire pour déterminer si une chaîne est un simple Int:

"324".toIntOption.isDefined // true
"à32".toIntOption.isDefined // false
"024".toIntOption.isDefined // true
0
Xavier Guihot