【问题标题】:How to check to see if a string is a decimal number in Scala如何检查字符串是否是Scala中的十进制数
【发布时间】:2012-03-30 06:38:51
【问题描述】:

我对 Scala 还很陌生,我几乎每天都在发现新的有趣的做事方式,但它们并不总是明智的,有时已经作为一种结构存在于语言中,我只是不知道他们。所以,有了这个序言,我正在检查给定的字符串是否完全由数字组成,所以我正在这样做:

def isAllDigits(x: String) = x.map(Character.isDigit(_)).reduce(_&&_)

这是明智的还是不必要的愚蠢?它有更好的方法吗?只是调用 x.toInt 并捕获异常更好,还是不那么惯用?两者都有性能优势/缺点吗?

【问题讨论】:

  • 请注意,您的问题的答案将确定String 是否仅包含数字,但不能确定它是否适合IntLong。 @Tvaroh 的回答将保证结果将“适合”适当的数字类型。

标签: scala


【解决方案1】:

试试这个:

def isAllDigits(x: String) = x forall Character.isDigit

forall 接受一个函数(在本例中为Character.isDigit),该函数接受一个属于集合元素类型的参数并返回一个Boolean;如果函数为集合中的所有元素返回true,则返回true,否则返回false

【讨论】:

  • 啊!太棒了,这就是我想要的特殊酱汁,我不得不相信语言中有一种结构可以做到这一点!现在我想知道是否有一个类似的结构可能适用于任何人,所以不是减少逻辑与,而是减少逻辑或?
  • isAllDigits("") 返回true。此代码为空字符串返回falsedef isAllDigits(x: String) = (x!="") && (x forall Character.isDigit)
  • 对于像 "9.0" 这样的字符串返回 false
  • @Phoenix 当然,因为.(小数点)不是数字。
【解决方案2】:

Scala 2.13开始,我们可以使用String::toDoubleOption,判断一个String是否为十进制数:

"324.56".toDoubleOption.isDefined // true
"4.06e3".toDoubleOption.isDefined // true
"9w01.1".toDoubleOption.isDefined // false

判断字符串是否为简单 Int 的类似选项:

"324".toIntOption.isDefined // true
"à32".toIntOption.isDefined // false
"024".toIntOption.isDefined // true

【讨论】:

  • Tis 不适用于 "NaN".toDoubleOption.isDefined(返回 true)
【解决方案3】:

你想知道字符串是否为整数吗?然后.toInt 它并捕获异常。您是否想知道字符串是否全是数字?然后问一个:

s.forall(_.isDigit)
s matches """\d+"""

【讨论】:

  • 我猜最后一个只检查字符串是否包含任何数字。正确的正则表达式是 """^\d+$""",如果空字符串也应该算作 "digit",则为 """^\d*$"""。
  • @Ixx - 我看到你不明白 Java 正则表达式如何与各种方法一起工作。
  • 各种方法是什么意思?我只是在那里看到 \d+ ,它通常会检查字符串中某处的数字。但是,是的,我在 Java 或 Scala 中使用正则表达式的工作并不多,所以也许我错过了你的正则表达式的工作方式 ^\d+$
  • @Ixx - matches 需要完全匹配。还有其他方法可以将正则表达式绑定到例如第一次出现。
  • @dbau - 确实。 “所有数字”与“是整数”不同。
【解决方案4】:

您可以简单地为此使用正则表达式。

val onlyDigitsRegex = "^\\d+$".r

def isAllDigits(x: String) = x match {
  case onlyDigitsRegex() => true
  case _ => false
}

或者干脆

def isAllDigits(x: String) = x.matches("^\\d+$")

为了稍微改进这一点,您可以使用 pimp my library 模式使其成为字符串上的方法:

implicit def AllDigits(x: String) = new { def isAllDigits = x.matches("^\\d+$") }

"12345".isAllDigits // => true
"12345foobar".isAllDigits // => false

【讨论】:

    【解决方案5】:

    您也可以考虑这样的事情:

    import scala.util.control.Exception.allCatch
    
    def isLongNumber(s: String): Boolean = (allCatch opt s.toLong).isDefined
    // or
    def isDoubleNumber(s: String): Boolean = (allCatch opt s.toDouble).isDefined
    

    【讨论】:

    • 你将如何使用这个来区分小数和整数?
    • (allCatch opt s.toLong).isDefined 与 Try(s.toLong).isSuccess 相比有什么优势吗?
    • @sean_robbins 他们是等价的。不过,目前我会使用nonFatalCatch。不确定Try 是否捕捉到致命异常。
    • 非常好。通常这是我们需要的。 isDoubleNumber 适用于负数、分数、科学记数法 (1e-8),否则需要特殊处理。
    • @dbau def isDecimal(s: String) = isDoubleNumber(s) && !isLongNumber(s) def isRoundNumber(s: String) = isLongNumber(s)Long 的大小限制,无论如何。
    【解决方案6】:
    import scala.util.Try
    
    
    object NumCruncher {
    
      def isShort(aString: String): Boolean = Try(aString.toLong).isSuccess
      def isInt(aString: String): Boolean = Try(aString.toInt).isSuccess
      def isLong(aString: String): Boolean = Try(aString.toLong).isSuccess
      def isDouble(aString: String): Boolean = Try(aString.toDouble).isSuccess
      def isFloat(aString: String): Boolean = Try(aString.toFloat).isSuccess
    
      /**
       *
       * @param x the string to check
       * @return true if the parameter passed is a Java primitive number
       */
      def isNumber(x: String): Boolean = {
        List(isShort(x), isInt(x), isLong(x), isDouble(x), isFloat(x))
          .foldLeft(false)(_ || _)
      }
    
    }
    

    【讨论】:

      【解决方案7】:

      Try 在性能方面可能不是最佳选择,但除此之外它很整洁:

      scala> import scala.util.Try
      scala> Try{ "123x".toInt }
      res4: scala.util.Try[Int] = Failure(java.lang.NumberFormatException: For input string: "123x")
      scala> Try{ "123x".toInt }.isSuccess
      res5: Boolean = false
      

      【讨论】:

        【解决方案8】:

        @Jesper 的回答很到位。

        做我下面建议的事情(解释如下)

        由于您正在检查给定字符串是否为数字(标题表明您需要小数),因此假设您打算在 forall 保护通过时进行转换。

        一个简单的隐式作用域将节省多达 9 次击键 ;-)

        implicit def str2Double(x: String) = x.toDouble
        

        为什么这很危险

        def takesDouble(x: Double) = x
        

        编译器现在将允许takesDouble("runtime fail"),因为隐式尝试将您使用的任何字符串转换为 Double,成功的保证为零,哎呀。

        隐式转换似乎更适合在转换失败时提供可接受的默认值的情况(并非总是如此;因此谨慎使用隐式)

        【讨论】:

        • 很高兴知道,我还在研究隐式转换!
        • 是的,当我在写隐式时,我意识到,等一下,这在运行时很容易出错;-)
        【解决方案9】:

        还有一个:

          import scala.util.Try
        
          val doubleConverter: (String => Try[Double]) = (s: String) => Try{ s.map(c => if ((Character.isDigit(c) == true) || (c == '.')) Some(c) else None).flatten.mkString.toDouble }
        
          val d1: Try[Double] = doubleConverter("+ 1234.0%")
          val d2: Try[Double] = doubleConverter("+ 1234..0%")
        

        【讨论】:

          【解决方案10】:

          基于出色的 Jexter 解决方案,在这段代码中,我使用 Option 处理 NullPointerException:

              def isValidPositiveNumber(baseString: Option[String]): Boolean = baseString match {
                  case Some(code) => !code.isEmpty && (code forall Character.isDigit)
                  case None => false
                } 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-07-20
            • 2014-11-14
            • 2012-02-22
            • 2015-05-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多