【问题标题】:How to pattern match int strings?如何模式匹配 int 字符串?
【发布时间】:2017-03-23 16:05:32
【问题描述】:

我正在尝试找出在 Scala 中模式匹配 int 的字符串表示的最佳方式。我真正想做的是这样的:

"1234" match {
  // Some cases
  case "five" => 5
  case Int(i) => i // Fails
  case _ => throw new RuntimeException()
}

一种方法是使用正则表达式。这样做的一个潜在问题是它不会检测整数是否太大而无法放入 int。

val ISINT = "^([+-]?\\d+)$".r

"1234" match {
  case "five" => 5
  case ISINT(t) => t.toInt
  case _ => throw new RuntimeException()
}

另一种方法使用返回OptiontoInt 函数(借用自this blog post)。这很好,因为它使标准库确定字符串是否包含整数。问题是它迫使我将我的逻辑嵌套在我认为它应该平坦的地方。

def toInt(s: String): Option[Int] = {
  try {
    Some(s.toInt)
  } catch {
    case e: Exception => None
  }
}

"1234" match {
  case "five" => 5
  case t => toInt(t) match {
    case Some(i) => i
    case None => throw new RuntimeException()
  }
}

【问题讨论】:

标签: scala pattern-matching


【解决方案1】:

您可以像这样定义自定义提取器

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

并按照您的意愿使用它

"1234" match {
  // Some cases
  case "five" => 5
  case Int(i) => i // works :)
  case _ => throw new RuntimeException()
}

【讨论】:

    【解决方案2】:

    我真的很喜欢 @Jasper-M 的简单方法,但我会尽力而为 to avoid generating exceptions as a means of control flow-- 更不用说显着的性能成本了。有趣的是@Jasper-M 的方法是如此简洁和优雅,它隐藏了这些细节。

    因此,如果您想尝试一种基于非异常的方法来获得乐趣:

    val matcher = "1234" match {
      case "five" => Some(BigInt(5L))
      case regex(t) => Some(BigInt(t))
      case _ => None
    }
    val result: Option[Int] = matcher.filter(_.isValidInt).map(_.toInt)
    

    在这种情况下,您会得到一个Option[Int]],它是从StringNone 解析而来的一个好的IntSome

    我会先采用@Jasper-M 的方法并观察性能。如果您注意到任何问题,请考虑基于非异常的方法。

    【讨论】:

    • 如果整数对于Long 来说太大,则会引发异常。
    • 确实如此。我应该提到这一点。问题是在这种情况下这是否是合理的可能性。在现实世界中,重要的是针对实际的、可能的现实编写代码,而不是(可能)模糊的理论可能性。无论如何,这是一个分散了主要观点的小细节,即基于异常的解决方案很少应该是您的首选。但由于它困扰您,我提供了一个基于BigInt 的解决方案。
    【解决方案3】:

    正则表达式的另一个技巧

      "1234" match {
          case number if number.matches("\\d+") => println(s"yes its a numeric value  $number")
          case _                                => println("not a numeric value")
        }
    

    【讨论】:

      【解决方案4】:

      也许你可以在比赛中使用后卫?

      "12312312313123" match {
         case s: String if s.isInt => "int"
         case _ => "no int"
      }
      
      implicit class IsInt(i: String){
        def isInt: Boolean = Try(i.toInt).isSuccess
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 2018-10-04
        • 2016-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多