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?
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.
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+"""
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
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
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)(_ || _)
}
}
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
@ 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).
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%")
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
}
À 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