我想检查一个字符串是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)
前面的答案可以用,虽然它没有抓住所有的情况。例如,后缀为 f
或 d
可以解析为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
将停止,并返回第一个产生了 isSuccess
被 true
. 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
我不知道发布的代码如何工作。如果 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
}