java/kotlin:格式double/int,总位数固定

java/kotlin: format double/int with fixed total digits

我尝试四处搜索,但找不到针对此问题的完整解决方案: 我想格式化一个 Int 以便总位数始终为 3。举几个例子:

1000000 -> 1,00m
678945 -> 678k
65432 -> 65,4k
5437 -> 5,43k

数字绝不能小于 1000 或大于 10 亿,因此其他情况并不重要

这是我最接近的:

@JvmStatic
        fun formatPointsTop3(points: Int?): String {
            if (points == null) return ""

            val formatter = NumberFormat.getInstance(Locale.ITALIAN)
            val mathContext = MathContext(3, RoundingMode.DOWN)


            return when {
                points < 1000 -> {
                    "$points"
                }
                points < 1000000 -> {
                    val bigDecimal = BigDecimal(points / 1000.0, mathContext)
                    "${formatter.format(bigDecimal)}k"
                }
                else -> {
                    val bigDecimal = BigDecimal(points / 1000000.0, mathContext)
                    "${formatter.format(bigDecimal)}m"
                }
            }
        }

除了输出 1m(我想要 1.00m)的 1000000 之外,这在大多数情况下都可以正常工作。添加 formatter.minimumFractionDigits = 2 为所有数字添加小数。

有没有办法在不直接在字符串上做奇怪的事情的情况下实现这一点?

应该有。首先,弄清楚你想要如何呈现它,这似乎你对每个 log(n) 的确切方式有不同的看法(例如,输入中有多少位数字)。对于 7 位数字,您想要呈现值,divided by 100 万,具有 2 个小数位。对于 8 位数字,您需要值 div 百万和 1 个小数,等等。这将是很多代码,也许字符串操作更简单。

我最终这样做了:

fun formatPointsTop3(points: Int?): String {
            if (points == null) return ""
            if (points == 0) return "0"

            val maxNumberOfDigits = 3

            val multiplierExponent = log(points.toDouble(), 1000.0).toInt()

            val bigPoints = BigDecimal(points)
            val bigDivider = BigDecimal(1000).pow(multiplierExponent)
            val reducedPoints = bigPoints.divide(bigDivider)

            val intPart = reducedPoints.toBigInteger().toInt()
            val decimalPart = reducedPoints.subtract(BigDecimal(intPart)).toDouble()

            val numberOfDecimals = maxNumberOfDigits - (log10(intPart.toDouble()).toInt() + 1)

            var formattedString = "$intPart"

            if (numberOfDecimals > 0) {
                val multiplier = 10.0.pow(numberOfDecimals)
                val formatter = NumberFormat.getIntegerInstance()
                formatter.minimumIntegerDigits = numberOfDecimals
                formatter.maximumIntegerDigits = numberOfDecimals
                val multiplied = (decimalPart * multiplier).toInt()
                formattedString += ",${formatter.format(multiplied)}"
            }

            formattedString += when (multiplierExponent) {
                0 -> ""
                1 -> "k"
                2 -> "m"
                3 -> "b"
                else -> ""  //this is not possible as max int is 2 billions
            }

            return formattedString
        }

它很丑,但它看起来比字符串操作好