Scala: coincide y analizar una cadena de número entero?
Pregunta
Estoy buscando una manera de igualar una cadena que puede contener un valor entero. Si es así, analizarlo. Me gustaría escribir código similar al siguiente:
def getValue(s: String): Int = s match {
case "inf" => Integer.MAX_VALUE
case Int(x) => x
case _ => throw ...
}
El objetivo es que si la cadena es igual a "inf", el retorno Integer.MAX_VALUE. Si la cadena es un número entero apta para su procesamiento, devolver el valor entero. De lo contrario tirar.
Solución
Definir un extractor
object Int {
def unapply(s : String) : Option[Int] = try {
Some(s.toInt)
} catch {
case _ : java.lang.NumberFormatException => None
}
}
Su método de ejemplo
def getValue(s: String): Int = s match {
case "inf" => Integer.MAX_VALUE
case Int(x) => x
case _ => error("not a number")
}
Y su uso
scala> getValue("4")
res5: Int = 4
scala> getValue("inf")
res6: Int = 2147483647
scala> getValue("helloworld")
java.lang.RuntimeException: not a number
at scala.Predef$.error(Predef.scala:76)
at .getValue(<console>:8)
at .<init>(<console>:7)
at .<clinit>(<console>)
at RequestResult$.<init>(<console>:4)
at RequestResult$.<clinit>(<console>)
at RequestResult$result(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Na...
Otros consejos
Sé que esto es un viejo, pregunta respondida, pero esto es mejor en mi humilde opinión:
scala> :paste
// Entering paste mode (ctrl-D to finish)
val IntRegEx = "(\\d+)".r
def getValue(s: String): Option[Int] = s match {
case "inf" => Some(Integer.MAX_VALUE)
case IntRegEx(num) => Some(num.toInt)
case _ => None
}
// Exiting paste mode, now interpreting.
IntRegEx: scala.util.matching.Regex = (\d+)
getValue: (s: String)Option[Int]
scala> getValue("inf")
res21: Option[Int] = Some(2147483647)
scala> getValue("123412")
res22: Option[Int] = Some(123412)
scala> getValue("not-a-number")
res23: Option[Int] = None
Por supuesto, no lanzar ninguna excepción, pero si realmente lo desea, puede utilizar
getValue(someStr) getOrElse error("NaN")
Se puede usar un protector:
def getValue(s: String): Int = s match {
case "inf" => Integer.MAX_VALUE
case _ if s.matches("[+-]?\\d+") => Integer.parseInt(s)
}
¿Qué hay de:
def readIntOpt(x: String) =
if (x == "inf")
Some(Integer.MAX_VALUE)
else
scala.util.Try(x.toInt).toOption
def getValue(s: String): Int = s match {
case "inf" => Integer.MAX_VALUE
case _ => s.toInt
}
println(getValue("3"))
println(getValue("inf"))
try {
println(getValue("x"))
}
catch {
case e => println("got exception", e)
// throws a java.lang.NumberFormatException which seems appropriate
}
una versión mejorada del extractor de James Iry:
object Int {
def unapply(s: String) = scala.util.Try(s.toInt).toOption
}
Desde Scala 2.13
introducido String::toIntOption
:
"5".toIntOption // Option[Int] = Some(5)
"abc".toIntOption // Option[Int] = None
podemos emitir el String
como Option[Int]
después de comprobar si es igual a "inf":
if (str == "inf") Some(Int.MaxValue) else str.toIntOption
// "inf" => Option[Int] = Some(2147483647)
// "347" => Option[Int] = Some(347)
// "ac4" => Option[Int] = None