Scala:如何匹配和解析整数字符串?

25
我正在寻找一种方法来匹配可能包含整数值的字符串。如果有,解析它。我想编写类似以下代码的代码:

我正在寻找一种匹配可能包含整数值的字符串的方法。如果有,解析它。我希望编写类似以下代码的代码:

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

这个目标是如果字符串等于"inf",则返回Integer.MAX_VALUE。如果该字符串可以转换为整数,则返回整数值。否则抛出异常。

7个回答

41

定义一个提取器

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

您的示例方法

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

并使用它

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

所以你可以打开一个 { } 对象,像这样添加方法到现有的类吗?很酷(我想...)。 - Landon Kuhn
没关系,我现在明白了,对象Int{}正在你的命名空间中创建一个新的Int类。 - Landon Kuhn
6
使用正则表达式匹配字符串内容,可能比捕获异常更有效率。 - Daniel Spiewak
1
@DanielSpiewak,这是因为异常破坏了引用透明性吗? - Kevin Meredith

11

我认为这样更好:

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

当然,它不会抛出任何异常,但如果您真的想要,可以使用:

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

如果您将“20100200300”作为值传递,您将会得到一个异常。它会通过您的正则表达式,但是这个数字太大了,无法转换成整数并抛出异常。 - NateH06
@NateH06 你是对的,而且被选中的答案似乎没有那个缺陷。应该有一个 case 来捕获那些太大的数字,或者我们可以使用 scala.math.BigInt 来代替。 - rsenna

8
您可以使用守卫(guard):
def getValue(s: String): Int = s match {
  case "inf" => Integer.MAX_VALUE 
  case _ if s.matches("[+-]?\\d+")  => Integer.parseInt(s)
}

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

1

James Iry的提取器的改进版本:

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

1
自从Scala 2.13引入了String::toIntOption之后:
"5".toIntOption   // Option[Int] = Some(5)
"abc".toIntOption // Option[Int] = None

在检查字符串是否等于"inf"后,我们可以将String转换为Option[Int]

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

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
}

这实际上是满足我当前需求的好方法,但它并不是我正在寻找的通用解决方案。例如,也许我想根据字符串可解析为什么类型来执行一个代码块: def doSomething(s: String): Int = s match { case Int(x) => println("你得到了一个整数") case Float(x) => println("你得到了一个浮点数") case _ => throw ... } - Landon Kuhn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接