25

I'm looking for a way to matching a string that may contain an integer value. If so, parse it. I'd like to write code similar to the following:

  def getValue(s: String): Int = s match {
       case "inf" => Integer.MAX_VALUE 
       case Int(x) => x
       case _ => throw ...
  }

The goal is that if the string equals "inf", return Integer.MAX_VALUE. If the string is a parsable integer, return the integer value. Otherwise throw.

7 Answers 7

41

Define an extractor

object Int {
  def unapply(s : String) : Option[Int] = try {
    Some(s.toInt)
  } catch {
    case _ : java.lang.NumberFormatException => None
  }
}

Your example method

def getValue(s: String): Int = s match {
  case "inf" => Integer.MAX_VALUE 
  case Int(x) => x
  case _ => error("not a number")
}

And using it

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...
Sign up to request clarification or add additional context in comments.

4 Comments

So you can just open up an object { } like that and add methods to an existing class? Cool (I think...).
Never mind, I understand now that object Int{} is creating a new Int class in your namespace.
It actually might be more efficient to use regular expressions to match the contents of the string, rather than catching the exception.
@DanielSpiewak, is that due to exceptions breaking Referential Transparency?
11

This is better IMHO:

val IntRegEx = "(\\d+)".r
def getValue(s: String): Option[Int] =
  s match {
    case "inf"         => Some(Int.MaxValue)
    case IntRegEx(num) => Some(num.toInt)
    case _             => None
  }

getValue("inf")          // Some(2147483647)
getValue("123412")       // Some(123412)
getValue("not-a-number") // None

Of course, it doesn't throw any exceptions, but if you really want it, you may use:

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

2 Comments

If you pass "20100200300" as the value, you're going to get an exception. It'll pass your regex but that's (no moon) too big to be an Int and throw an exception.
@NateH06 You're right, and the chosen answer does not have that flaw it seems. There should be a case catching those too-big number, or maybe we could use scala.math.BigInt instead.
8

You could use a guard:

def getValue(s: String): Int = s match {
  case "inf" => Integer.MAX_VALUE 
  case _ if s.matches("[+-]?\\d+")  => Integer.parseInt(s)
}

Comments

5

How about:

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

Comments

1

an improved version of James Iry's extractor:

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

Comments

1

Since Scala 2.13 introduced String::toIntOption:

"5".toIntOption   // Option[Int] = Some(5)
"abc".toIntOption // Option[Int] = None

we can cast the String as an Option[Int] after checking if it's equal to "inf":

if (str == "inf") Some(Int.MaxValue) else str.toIntOption
// "inf"   =>   Option[Int] = Some(2147483647)
// "347"   =>   Option[Int] = Some(347)
// "ac4"   =>   Option[Int] = None

Comments

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

1 Comment

This is actually a good way to meet my immediate needs, however it's not the generic solution i was looking for. For instance, perhaps I would want to execute a block depending on what type the string was parsable to: def doSomething(s: String): Int = s match { case Int(x) => println("you got an int") case Float(x) => println("you got a float") case _ => throw ... }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.