检查字符串是int, long, float, boolean还是double。

问题描述 投票:0回答:1

我想检查一个字符串是int、long、float、double还是boolean。

例如,"1 "应该是int,"1.22 "应该是float,"1.5555555 "应该是double。

这是我所能做到的最好的。

case item: String =>

        if (item.toInt.toString.equals(item)) {
          arrayType = Int.getClass
          ByteBuffer.allocate(4 * array.length)
        }
        else if (item.toLong.toString.equals(item)) {
          arrayType = Long.getClass
          ByteBuffer.allocate(8 * array.length)
        }
        else if (item.toFloat.toString.equals(item)) {
          arrayType = Float.getClass
          ByteBuffer.allocate(4 * array.length)
        }
        else if (item.toDouble.toString.equals(item)) {
          arrayType = Double.getClass
          ByteBuffer.allocate(8 * array.length)
        }
        else if (item.toBoolean.toString.equals(item)) {
          arrayType = Boolean.getClass
          ByteBuffer.allocate(array.length)
        }

        else throw new UnsupportedOperationException("Type not supported: " + item.getClass)
scala
1个回答
1
投票

前面的答案可以用,虽然它没有抓住所有的情况。例如,后缀为 fd 可以解析为Double或Float,也可以解析为某些字符串,如 "Infinity "或"-Infinity"。举个例子:"-Infinity "或"-Infinity"。"12.1234567893901f".toFloat -> 12.123457"NaN".toFloat -> NaN. 科学或 "E "记号 也可以解析为FloatsDoubles(变成了 ±Infinity 如果需要的话)。)

  • item.getClass 将永远 String 中,所以 "Type not supported "的错误信息可能会产生误导,您可能更倾向于使用 IllegalArgumentException 附言 item 而不是 item.getClass.
  • 检查 s.toXXX.toString.equals(s) 的值就不行了。s 可以成功解析,但属于 "未简化"。一种情况是一长串数字。"61234817390131412313458".toDouble.toString = "6.123481739013142E22". 其他 "未简化 "的值也是如此,例如: 。"+0".toFloat.toString = "0.0"
  • 正如评论和前面的答案中提到的,每个 toXXX 方法可能会抛出一个错误,所以要想尝试所有的方法,可以用一个 Try. 该 find 办法 List 将停止,并返回第一个产生了 isSuccesstrue.
  • 如果 s.toFloat 没有出现错误,那么 s.toDouble 不会抛出一个错误,反之亦然。两者应该一起成功或失败。因此,需要做进一步的检查,看看哪一个更合适(但 toString.equals 可能是太具体了,如前所述)。)
    • 某些(非常正或负的)值会变成 ±Infinity 当解析成一个float时,但不是double。如果一个输入被强制转换成 Infinity 漂浮 Double那么,你可能更喜欢一个 Double. 如果输入解析为 Infinity 两种类型,然后选择其中一种类型。
    • 太小的输入将被迫提前归零,对于 Float 比起 Double.

这是一个可能的函数定义的大纲。

object t {
  type Result = (Int, Class[_])
  type ListElt = (Result, String => Any)
  def useFloat(s:String): Boolean = {
    // determine if choosing Float is "desirable"
    val floatVal:Float = s.toFloat
    val doubleVal:Double = s.toDouble
    // if very little precision is lost, or if the maximum information stored isn't lost completely
    val MAX_LOST:Double = 1E-5.min(doubleVal)
    val preservedPrecision:Boolean = (floatVal - doubleVal).abs <= MAX_LOST
    // Remove this variable if `Double` is preferred when bothInfinite
    val bothInfinite:Boolean = floatVal.isInfinite && doubleVal.isInfinite
    preservedPrecision || bothInfinite
  }
  def getSizeAndType(s: String): Option[Result] = {
    val floatResult:Result = (4, Float.getClass)
    val doubleResult:Result = (8, Double.getClass)
    val conversions: List[ListElt] = List(
      ((4, Int.getClass), ((x: String) => x.toInt)),
      ((8, Long.getClass), ((x: String) => x.toLong)),
      (floatResult, ((x: String) => x.toFloat)),
      (doubleResult, ((x: String) => x.toDouble)),
      ((1, Boolean.getClass), ((x: String) => x.toBoolean))
    )
    val firstSuccess: Option[ListElt] = conversions.find((elt: ListElt) => scala.util.Try(elt._2(s)).isSuccess)
    val result = firstSuccess.map(_._1)
    // check if choosing Float is "desirable"
    result match {
      case Some(`floatResult`) =>
        if (useFloat(s)){
          Some(floatResult)
        } else {
          Some(doubleResult)
        }
      case other => other
    }
  }
  def handle(s:String) = {
    val (bytes, arrayType) = getSizeAndType(s).getOrElse(0, "None")
    if (bytes > 0) {
      // perform allocation
      //ByteBuffer.allocate(4 * array.length)
      println(s"${bytes}, ${arrayType}")
    } else {
      // throw exception, etc.
      println("Not parsable")
    }
  }
}

println(t.handle("9")) // 4, class scala.Int$
println(t.handle("1.9")) // 4, class scala.Float$
println(t.handle("2147483648")) // 8, class scala.Long$
println(t.handle("2.5769803776E9")) // 8, class scala.Double$ (small enough for finite float but loses enough precision)
println(t.handle("3.4028235E38")) // 8, class scala.Double$ (ditto)
println(t.handle("6.805647E38")) // 8, class scala.Double$ (too big for finite float)
println(t.handle("12.123456789")) // 4, class scala.Float$
println(t.handle("Infinity")) // 4, class scala.Float$
println(t.handle("false")) // 1, class scala.Boolean$
println(t.handle("xyz")) // Not parsable

4
投票

我不知道发布的代码如何工作。如果 item"true" 然后 .toInt 会扔,但永远不会到 .toBoolean 测试。

我很想用RegEx来做初始隔离,然后让 BigDecimal 做数字解析。

val isBool = "(?i)(?:true|false)".r
val isNum = raw"\d*\.?\d+".r

item match {
  case isBool() => ...
  case isNum() =>
    val bd = BigDecimal(item)
    if      (bd.isValidInt)      ...
    else if (bd.isValidLong)     ...
    else if (bd.isDecimalFloat)  ...
    else if (bd.isDecimalDouble) ...
    else //too big to fit?
  case _ => //report bad item
}
© www.soinside.com 2019 - 2024. All rights reserved.