2009-07-02 12 views
23

Estoy buscando una manera de hacer coincidir una cadena que pueda contener un valor entero. Si es así, analízalo. Me gustaría escribir código similar al siguiente:Scala: coincide y analiza una cadena de enteros?

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 entero analizable, devuelve el valor entero. De lo contrario tirar.

Respuesta

38

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... 
+0

Así que puedes abrir un objeto {} así y agregar métodos a un existente ¿clase? Genial (creo ...). –

+0

No importa, ahora entiendo que el objeto Int {} está creando una nueva clase Int en su espacio de nombres. –

+3

En realidad, podría ser más eficiente usar expresiones regulares para hacer coincidir el contenido de la cadena, en lugar de capturar la excepción. –

1
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 
} 
+0

Esto es realmente una buena manera de satisfacer mis necesidades inmediatas, sin embargo, no es la solución genérica que estaba buscando. Por ejemplo, tal vez me gustaría ejecutar un bloque dependiendo de qué tipo era analizable la cadena: def doSomething (s: String): Int = s coincidencia { caso Int (x) => println ("tiene una int ") caso Float (x) => println (" tienes un flotador ") case _ => throw ... } –

8

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) 
} 
9

Sé que esto es un viejo, respondió a la pregunta, 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 lanza ninguna excepción, pero si realmente lo desea, puede utilizar

getValue(someStr) getOrElse error("NaN") 
4

¿Qué tal:

def readIntOpt(x: String) = 
    if (x == "inf") 
    Some(Integer.MAX_VALUE) 
    else 
    scala.util.Try(x.toInt).toOption 
1

una versión mejorada del extractor de James Iry:

object Int { 
    def unapply(s: String) = scala.util.Try(s.toInt).toOption 
} 
Cuestiones relacionadas