如何在 java 中格式化1200到1.2 k

我想用 java 把下面的数字格式化成它们旁边的数字:

1000 to 1k
5821 to 5.8k
10500 to 10k
101800 to 101k
2000000 to 2m
7800000 to 7.8m
92150000 to 92m
123200000 to 123m

右边的数字是长数或整数,左边的数字是字符串。 我该怎么做。我已经为此做了一些算法,但我认为可能已经有一些发明在那里做更好的工作,并且不需要额外的测试,如果我开始处理数十亿和万亿:)

附加要求:

  • 格式应该最多有4个字符
  • 上面的意思是1.1 k 是 OK,11.2 k 不是。同样的7.8米是可以的19.1米不是。在小数点前只允许有一位数字有小数点。小数点前两位表示不是小数点后两位。
  • 不需要四舍五入。(数字被显示与 k 和 m 附加是更多的模拟规范表明近似不精确的逻辑条款。因此四舍五入是不相关的,主要是由于变量的性质,即使在查看缓存结果时,它也可以增加或减少数位。)
77688 次浏览

我的 Java 已经生疏了,但是我会这样在 C # 中实现它:

private string  FormatNumber(double value)
{
string[]  suffixes = new string[] {" k", " m", " b", " t", " q"};
for (int j = suffixes.Length;  j > 0;  j--)
{
double  unit = Math.Pow(1000, j);
if (value >= unit)
return (value / unit).ToString("#,##0.0") + suffixes[--j];
}
return value.ToString("#,##0");
}

这很容易调整到使用 CS 公斤(1,024)而不是公斤,或者增加更多的单位。它将1.000格式化为“1.0 k”而不是“1 k”,但我相信这并不重要。

为了满足更具体的要求“不超过4个字符”,删除后缀前的空格并像下面这样调整中间块:

if (value >= unit)
{
value /= unit;
return (value).ToString(value >= unit * 9.95 ? "#,##0" : "#,##0.0") + suffixes[--j];
}

我知道,这看起来更像一个 C 程序,但它是超级轻量级!

public static void main(String args[]) {
long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(long n : numbers) {
System.out.println(n + " => " + coolFormat(n, 0));
}
}


private static char[] c = new char[]{'k', 'm', 'b', 't'};


/**
* Recursive implementation, invokes itself for each factor of a thousand, increasing the class on each invokation.
* @param n the number to format
* @param iteration in fact this is the class from the array c
* @return a String representing the number n formatted in a cool looking way.
*/
private static String coolFormat(double n, int iteration) {
double d = ((long) n / 100) / 10.0;
boolean isRound = (d * 10) %10 == 0;//true if the decimal part is equal to 0 (then it's trimmed anyway)
return (d < 1000? //this determines the class, i.e. 'k', 'm' etc
((d > 99.9 || isRound || (!isRound && d > 9.99)? //this decides whether to trim the decimals
(int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal
) + "" + c[iteration])
: coolFormat(d, iteration+1));


}

产出:

1000 => 1k
5821 => 5.8k
10500 => 10k
101800 => 101k
2000000 => 2m
7800000 => 7.8m
92150000 => 92m
123200000 => 123m
9999999 => 9.9m

需要一些改进,但是: 严格数学拯救!
你可以把后缀放在字符串或者数组中,然后根据电源或者类似的东西来获取它们。
除法也可以围绕权力进行管理,我认为几乎一切都是关于权力的价值。 希望能有帮助!

public static String formatValue(double value) {
int power;
String suffix = " kmbt";
String formattedNumber = "";


NumberFormat formatter = new DecimalFormat("#,###.#");
power = (int)StrictMath.log10(value);
value = value/(Math.pow(10,(power/3)*3));
formattedNumber=formatter.format(value);
formattedNumber = formattedNumber + suffix.charAt(power/3);
return formattedNumber.length()>4 ?  formattedNumber.replaceAll("\\.[0-9]+", "") : formattedNumber;
}

产出:

999
1200万
九万八
911K
110万
11B
712b
34t

下面是一个使用 DecimalFormat 工程符号的解决方案:

public static void main(String args[]) {
long[] numbers = new long[]{7, 12, 856, 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(long number : numbers) {
System.out.println(number + " = " + format(number));
}
}


private static String[] suffix = new String[]{"","k", "m", "b", "t"};
private static int MAX_LENGTH = 4;


private static String format(double number) {
String r = new DecimalFormat("##0E0").format(number);
r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);
while(r.length() > MAX_LENGTH || r.matches("[0-9]+\\.[a-z]")){
r = r.substring(0, r.length()-2) + r.substring(r.length() - 1);
}
return r;
}

产出:

7 = 7
12 = 12
856 = 856
1000 = 1k
5821 = 5.8k
10500 = 10k
101800 = 102k
2000000 = 2m
7800000 = 7.8m
92150000 = 92m
123200000 = 123m
9999999 = 10m

重症监护室有一个基于规则的数字格式化程序,可用于数字拼写等。我认为使用 ICU 会给你一个可读性和可维护的解决方案。

[用法]

正确的类是 RuleBasedNumberFormat。格式本身可以存储为单独的文件(或者作为 String 常量 IIRC)。

来自 http://userguide.icu-project.org/formatparse/numbers的例子

double num = 2718.28;
NumberFormat formatter =
new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT);
String result = formatter.format(num);
System.out.println(result);

同一页显示的是罗马数字,所以我想你的情况应该也是可能的。

我的最爱。您也可以使用“ k”等作为十进制的指示符,这在电子领域中很常见。这将给你一个额外的数字没有额外的空间

第二列尝试使用尽可能多的数字

1000 => 1.0k | 1000
5821 => 5.8k | 5821
10500 => 10k | 10k5
101800 => 101k | 101k
2000000 => 2.0m | 2m
7800000 => 7.8m | 7m8
92150000 => 92m | 92m1
123200000 => 123m | 123m
9999999 => 9.9m | 9m99

这是密码

public class HTTest {
private static String[] unit = {"u", "k", "m", "g", "t"};
/**
* @param args
*/
public static void main(String[] args) {
int[] numbers = new int[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
for(int n : numbers) {
System.out.println(n + " => " + myFormat(n) + " | " + myFormat2(n));
}
}


private static String myFormat(int pN) {
String str = Integer.toString(pN);
int len = str.length ()-1;
if (len <= 3) return str;
int level = len / 3;
int mode = len % 3;
switch (mode) {
case 0: return str.substring(0, 1) + "." + str.substring(1, 2) + unit[level];
case 1: return str.substring(0, 2) + unit[level];
case 2: return str.substring(0, 3) + unit[level];
}
return "how that?";
}
private static String trim1 (String pVal) {
if (pVal.equals("0")) return "";
return pVal;
}
private static String trim2 (String pVal) {
if (pVal.equals("00")) return "";
return pVal.substring(0, 1) + trim1(pVal.substring(1,2));
}
private static String myFormat2(int pN) {
String str = Integer.toString(pN);
int len = str.length () - 1;
if (len <= 3) return str;
int level = len / 3;
int mode = len % 3;
switch (mode) {
case 0: return str.substring(0, 1) + unit[level] + trim2(str.substring(1, 3));
case 2: return str.substring(0, 3) + unit[level];
case 1: return str.substring(0, 2) + unit[level] + trim1(str.substring(2, 3));
}
return "how that?";
}
}
//code longer but work sure...


public static String formatK(int number) {
if (number < 999) {
return String.valueOf(number);
}


if (number < 9999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 1);
String str2 = strNumber.substring(1, 2);
if (str2.equals("0")) {
return str1 + "k";
} else {
return str1 + "." + str2 + "k";
}
}


if (number < 99999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 2);
return str1 + "k";
}


if (number < 999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 3);
return str1 + "k";
}


if (number < 9999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 1);
String str2 = strNumber.substring(1, 2);
if (str2.equals("0")) {
return str1 + "m";
} else {
return str1 + "." + str2 + "m";
}
}


if (number < 99999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 2);
return str1 + "m";
}


if (number < 999999999) {
String strNumber = String.valueOf(number);
String str1 = strNumber.substring(0, 3);
return str1 + "m";
}


NumberFormat formatterHasDigi = new DecimalFormat("###,###,###");
return formatterHasDigi.format(number);
}

我不知道这是不是最好的办法,但我就是这么做的。

7=>7
12=>12
856=>856
1000=>1.0k
5821=>5.82k
10500=>10.5k
101800=>101.8k
2000000=>2.0m
7800000=>7.8m
92150000=>92.15m
123200000=>123.2m
9999999=>10.0m

- 密码

public String Format(Integer number){
String[] suffix = new String[]{"k","m","b","t"};
int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
if (size >= 3){
while (size % 3 != 0) {
size = size - 1;
}
}
double notation = Math.pow(10, size);
String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
return result
}

当前答案的问题

  • 当前的许多解决方案都使用这些前缀 k = 103,m = 106,b = 109,t = 1012。然而,根据 各种各样的 消息来源,正确的前缀是 k = 103,M = 106,G = 109,T = 1012
  • 缺乏对负数的支持(或者至少缺乏证明支持负数的测试)
  • 缺乏对逆运算的支持,例如将1.1 k 转换为1100(尽管这超出了原问题的范围)

Java 解决方案

这个解决方案(这个答案的扩展)解决了上述问题。

import org.apache.commons.lang.math.NumberUtils;


import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.regex.Pattern;




/**
* Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
* For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
*/
class RoundedMetricPrefixFormat extends Format {


private static final String[] METRIC_PREFIXES = new String[]{"", "k", "M", "G", "T"};


/**
* The maximum number of characters in the output, excluding the negative sign
*/
private static final Integer MAX_LENGTH = 4;


private static final Pattern TRAILING_DECIMAL_POINT = Pattern.compile("[0-9]+\\.[kMGT]");


private static final Pattern METRIC_PREFIXED_NUMBER = Pattern.compile("\\-?[0-9]+(\\.[0-9])?[kMGT]");


@Override
public StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {


Double number = Double.valueOf(obj.toString());


// if the number is negative, convert it to a positive number and add the minus sign to the output at the end
boolean isNegative = number < 0;
number = Math.abs(number);


String result = new DecimalFormat("##0E0").format(number);


Integer index = Character.getNumericValue(result.charAt(result.length() - 1)) / 3;
result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index]);


while (result.length() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
int length = result.length();
result = result.substring(0, length - 2) + result.substring(length - 1);
}


return output.append(isNegative ? "-" + result : result);
}


/**
* Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
* the original number because <tt>format()</tt> is a lossy operation, e.g.
*
* <pre>
* {@code
* def formatter = new RoundedMetricPrefixFormat()
* Long number = 5821L
* String formattedNumber = formatter.format(number)
* assert formattedNumber == '5.8k'
*
* Long parsedNumber = formatter.parseObject(formattedNumber)
* assert parsedNumber == 5800
* assert parsedNumber != number
* }
* </pre>
*
* @param source a number that may have a metric prefix
* @param pos if parsing succeeds, this should be updated to the index after the last parsed character
* @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
*/
@Override
public Object parseObject(String source, ParsePosition pos) {


if (NumberUtils.isNumber(source)) {


// if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
pos.setIndex(source.length());
return toNumber(source);


} else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {


boolean isNegative = source.charAt(0) == '-';
int length = source.length();


String number = isNegative ? source.substring(1, length - 1) : source.substring(0, length - 1);
String metricPrefix = Character.toString(source.charAt(length - 1));


Number absoluteNumber = toNumber(number);


int index = 0;


for (; index < METRIC_PREFIXES.length; index++) {
if (METRIC_PREFIXES[index].equals(metricPrefix)) {
break;
}
}


Integer exponent = 3 * index;
Double factor = Math.pow(10, exponent);
factor *= isNegative ? -1 : 1;


pos.setIndex(source.length());
Float result = absoluteNumber.floatValue() * factor.longValue();
return result.longValue();
}


return null;
}


private static Number toNumber(String number) {
return NumberUtils.createNumber(number);
}
}

Groovy Solution

解决方案最初是用 Groovy 编写的,如下所示。

import org.apache.commons.lang.math.NumberUtils


import java.text.DecimalFormat
import java.text.FieldPosition
import java.text.Format
import java.text.ParsePosition
import java.util.regex.Pattern




/**
* Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
* For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
*/
class RoundedMetricPrefixFormat extends Format {


private static final METRIC_PREFIXES = ["", "k", "M", "G", "T"]


/**
* The maximum number of characters in the output, excluding the negative sign
*/
private static final Integer MAX_LENGTH = 4


private static final Pattern TRAILING_DECIMAL_POINT = ~/[0-9]+\.[kMGT]/


private static final Pattern METRIC_PREFIXED_NUMBER = ~/\-?[0-9]+(\.[0-9])?[kMGT]/


@Override
StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {


Double number = obj as Double


// if the number is negative, convert it to a positive number and add the minus sign to the output at the end
boolean isNegative = number < 0
number = Math.abs(number)


String result = new DecimalFormat("##0E0").format(number)


Integer index = Character.getNumericValue(result.charAt(result.size() - 1)) / 3
result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index])


while (result.size() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
int length = result.size()
result = result.substring(0, length - 2) + result.substring(length - 1)
}


output << (isNegative ? "-$result" : result)
}


/**
* Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
* the original number because <tt>format()</tt> is a lossy operation, e.g.
*
* <pre>
* {@code
* def formatter = new RoundedMetricPrefixFormat()
* Long number = 5821L
* String formattedNumber = formatter.format(number)
* assert formattedNumber == '5.8k'
*
* Long parsedNumber = formatter.parseObject(formattedNumber)
* assert parsedNumber == 5800
* assert parsedNumber != number
* }
* </pre>
*
* @param source a number that may have a metric prefix
* @param pos if parsing succeeds, this should be updated to the index after the last parsed character
* @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
*/
@Override
Object parseObject(String source, ParsePosition pos) {


if (source.isNumber()) {


// if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
pos.index = source.size()
toNumber(source)


} else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {


boolean isNegative = source[0] == '-'


String number = isNegative ? source[1..-2] : source[0..-2]
String metricPrefix = source[-1]


Number absoluteNumber = toNumber(number)


Integer exponent = 3 * METRIC_PREFIXES.indexOf(metricPrefix)
Long factor = 10 ** exponent
factor *= isNegative ? -1 : 1


pos.index = source.size()
(absoluteNumber * factor) as Long
}
}


private static Number toNumber(String number) {
NumberUtils.createNumber(number)
}
}

测试(Groovy)

测试是用 Groovy 编写的,但是可以用来验证 Java 或 Groovy 类(因为它们都有相同的名称和 API)。

import java.text.Format
import java.text.ParseException


class RoundedMetricPrefixFormatTests extends GroovyTestCase {


private Format roundedMetricPrefixFormat = new RoundedMetricPrefixFormat()


void testNumberFormatting() {


[
7L         : '7',
12L        : '12',
856L       : '856',
1000L      : '1k',
(-1000L)   : '-1k',
5821L      : '5.8k',
10500L     : '10k',
101800L    : '102k',
2000000L   : '2M',
7800000L   : '7.8M',
(-7800000L): '-7.8M',
92150000L  : '92M',
123200000L : '123M',
9999999L   : '10M',
(-9999999L): '-10M'
].each { Long rawValue, String expectedRoundValue ->


assertEquals expectedRoundValue, roundedMetricPrefixFormat.format(rawValue)
}
}


void testStringParsingSuccess() {
[
'7'    : 7,
'8.2'  : 8.2F,
'856'  : 856,
'-856' : -856,
'1k'   : 1000,
'5.8k' : 5800,
'-5.8k': -5800,
'10k'  : 10000,
'102k' : 102000,
'2M'   : 2000000,
'7.8M' : 7800000L,
'92M'  : 92000000L,
'-92M' : -92000000L,
'123M' : 123000000L,
'10M'  : 10000000L


].each { String metricPrefixNumber, Number expectedValue ->


def parsedNumber = roundedMetricPrefixFormat.parseObject(metricPrefixNumber)
assertEquals expectedValue, parsedNumber
}
}


void testStringParsingFail() {


shouldFail(ParseException) {
roundedMetricPrefixFormat.parseObject('notNumber')
}
}
}

添加我自己的答案,Java 代码,自解释代码. 。

import java.math.BigDecimal;


/**
* Method to convert number to formatted number.
*
* @author Gautham PJ
*/
public class ShortFormatNumbers
{


/**
* Main method. Execution starts here.
*/
public static void main(String[] args)
{


// The numbers that are being converted.
int[] numbers = {999, 1400, 2500, 45673463, 983456, 234234567};




// Call the "formatNumber" method on individual numbers to format
// the number.
for(int number : numbers)
{
System.out.println(number + ": " + formatNumber(number));
}


}




/**
* Format the number to display it in short format.
*
* The number is divided by 1000 to find which denomination to be added
* to the number. Dividing the number will give the smallest possible
* value with the denomination.
*
* @param the number that needs to be converted to short hand notation.
* @return the converted short hand notation for the number.
*/
private static String formatNumber(double number)
{
String[] denominations = {"", "k", "m", "b", "t"};
int denominationIndex = 0;


// If number is greater than 1000, divide the number by 1000 and
// increment the index for the denomination.
while(number > 1000.0)
{
denominationIndex++;
number = number / 1000.0;
}


// To round it to 2 digits.
BigDecimal bigDecimal = new BigDecimal(number);
bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_EVEN);




// Add the number with the denomination to get the final value.
String formattedNumber = bigDecimal + denominations[denominationIndex];
return formattedNumber;
}


}

这里是 适用于任何长值的解决方案,我发现它非常易读(核心逻辑在 format方法的底部三行中完成)。

它利用 TreeMap找到适当的后缀。令人惊讶的是,它比我以前编写的使用数组的解决方案更有效,而且更难读。

private static final NavigableMap<Long, String> suffixes = new TreeMap<> ();
static {
suffixes.put(1_000L, "k");
suffixes.put(1_000_000L, "M");
suffixes.put(1_000_000_000L, "G");
suffixes.put(1_000_000_000_000L, "T");
suffixes.put(1_000_000_000_000_000L, "P");
suffixes.put(1_000_000_000_000_000_000L, "E");
}


public static String format(long value) {
//Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
if (value < 0) return "-" + format(-value);
if (value < 1000) return Long.toString(value); //deal with easy case


Entry<Long, String> e = suffixes.floorEntry(value);
Long divideBy = e.getKey();
String suffix = e.getValue();


long truncated = value / (divideBy / 10); //the number part of the output times 10
boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
}

测试代码

public static void main(String args[]) {
long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};
String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};
for (int i = 0; i < numbers.length; i++) {
long n = numbers[i];
String formatted = format(n);
System.out.println(n + " => " + formatted);
if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);
}
}

重要提示: 对于像 99999999999999999L这样的数字,向 double转换的答案将会失败,并且返回 100P而不是 99P,因为 double使用 IEEE标准:

如果一个十进制字符串与 最多15有效数字转换为 IEEE 754双精度表示,然后转换回一个字符串具有相同数量的有效数字,那么最后的字符串应该匹配原来的。[ long最多19有效数字。]

System.out.println((long)(double)99999999999999992L); // 100000000000000000
System.out.println((long)(double)99999999999999991L); //  99999999999999984
// it is even worse for the logarithm:
System.out.println(Math.log10(99999999999999600L)); // 17.0
System.out.println(Math.log10(99999999999999500L)); // 16.999999999999996

此解决方案可以切断不需要的数字,并适用于所有 long 。简单但性能良好的实现(下面比较)。-120k 不能用4个字符来表示,即使 -0.1 M 也太长了,这就是为什么对于负数,5个字符必须是可以的:

private static final char[] magnitudes = {'k', 'M', 'G', 'T', 'P', 'E'}; // enough for long


public static final String convert(long number) {
String ret;
if (number >= 0) {
ret = "";
} else if (number <= -9200000000000000000L) {
return "-9.2E";
} else {
ret = "-";
number = -number;
}
if (number < 1000)
return ret + number;
for (int i = 0; ; i++) {
if (number < 10000 && number % 1000 >= 100)
return ret + (number / 1000) + '.' + ((number % 1000) / 100) + magnitudes[i];
number /= 1000;
if (number < 1000)
return ret + number + magnitudes[i];
}
}

else if开头的测试是必要的,因为最小值是 -(2^63),最大值是 (2^63)-1,因此如果 number == Long.MIN_VALUE的分配 number = -number将会失败。如果我们必须做一个检查,那么我们可以包括尽可能多的数字,而不只是检查 number == Long.MIN_VALUE

这个实现和得到最多赞成票(据说是目前最快的)的实现进行了比较,结果显示它是 超过5倍的速度(这取决于测试设置,但随着数字越来越多,增益越来越大,这个实现必须做更多的检查,因为它处理所有的情况,所以如果另一个将固定的差异将变得更大)。之所以这么快,是因为没有浮点运算、没有对数、没有幂、没有递归、没有正则表达式、没有复杂的格式化程序,并且最小化了创建的对象数量。


下面是测试程序:

public class Test {


public static void main(String[] args) {
long[] numbers = new long[20000000];
for (int i = 0; i < numbers.length; i++)
numbers[i] = Math.random() < 0.5 ? (long) (Math.random() * Long.MAX_VALUE) : (long) (Math.random() * Long.MIN_VALUE);
System.out.println(convert1(numbers) + " vs. " + convert2(numbers));
}


private static long convert1(long[] numbers) {
long l = System.currentTimeMillis();
for (int i = 0; i < numbers.length; i++)
Converter1.convert(numbers[i]);
return System.currentTimeMillis() - l;
}


private static long convert2(long[] numbers) {
long l = System.currentTimeMillis();
for (int i = 0; i < numbers.length; i++)
Converter2.coolFormat(numbers[i], 0);
return System.currentTimeMillis() - l;
}


}

可能的输出: 2309 vs. 11591(当只使用正数时大致相同,当反转执行顺序时更极端,可能与垃圾收集有关)

坚持我的评论,我会重视可读性高于性能,这里有一个版本,它应该清楚发生了什么(假设你以前使用过 BigDecimal) ,没有过多的注释(我相信自我文档化的代码) ,没有担心性能(因为我无法想象一个场景,你会想要这样做的数百万次,甚至性能成为一个考虑因素)。

这个版本:

  • 使用 BigDecimal来提高精度,避免舍入问题
  • 工程四舍五入的要求,由业务
  • 适用于其他舍入模式,例如 HALF_UP
  • 允许您调整精度(改变 REQUIRED_PRECISION)
  • 使用 enum来定义阈值,即可以很容易地调整为使用 KB/MB/GB/TB 而不是 k/m/b/t 等,当然也可以根据需要扩展到 TRILLION以外
  • 伴随着彻底的单元测试,因为问题中的测试用例没有测试边界
  • 应该适用于零和负数

Threshold.java :

import java.math.BigDecimal;


public enum Threshold {
TRILLION("1000000000000", 12, 't', null),
BILLION("1000000000", 9, 'b', TRILLION),
MILLION("1000000", 6, 'm', BILLION),
THOUSAND("1000", 3, 'k', MILLION),
ZERO("0", 0, null, THOUSAND);


private BigDecimal value;
private int zeroes;
protected Character suffix;
private Threshold higherThreshold;


private Threshold(String aValueString, int aNumberOfZeroes, Character aSuffix,
Threshold aThreshold) {
value = new BigDecimal(aValueString);
zeroes = aNumberOfZeroes;
suffix = aSuffix;
higherThreshold = aThreshold;
}


public static Threshold thresholdFor(long aValue) {
return thresholdFor(new BigDecimal(aValue));
}


public static Threshold thresholdFor(BigDecimal aValue) {
for (Threshold eachThreshold : Threshold.values()) {
if (eachThreshold.value.compareTo(aValue) <= 0) {
return eachThreshold;
}
}
return TRILLION; // shouldn't be needed, but you might have to extend the enum
}


public int getNumberOfZeroes() {
return zeroes;
}


public String getSuffix() {
return suffix == null ? "" : "" + suffix;
}


public Threshold getHigherThreshold() {
return higherThreshold;
}
}

NumberShortener.java :

import java.math.BigDecimal;
import java.math.RoundingMode;


public class NumberShortener {


public static final int REQUIRED_PRECISION = 2;


public static BigDecimal toPrecisionWithoutLoss(BigDecimal aBigDecimal,
int aPrecision, RoundingMode aMode) {
int previousScale = aBigDecimal.scale();
int previousPrecision = aBigDecimal.precision();
int newPrecision = Math.max(previousPrecision - previousScale, aPrecision);
return aBigDecimal.setScale(previousScale + newPrecision - previousPrecision,
aMode);
}


private static BigDecimal scaledNumber(BigDecimal aNumber, RoundingMode aMode) {
Threshold threshold = Threshold.thresholdFor(aNumber);
BigDecimal adjustedNumber = aNumber.movePointLeft(threshold.getNumberOfZeroes());
BigDecimal scaledNumber = toPrecisionWithoutLoss(adjustedNumber, REQUIRED_PRECISION,
aMode).stripTrailingZeros();
// System.out.println("Number: <" + aNumber + ">, adjusted: <" + adjustedNumber
// + ">, rounded: <" + scaledNumber + ">");
return scaledNumber;
}


public static String shortenedNumber(long aNumber, RoundingMode aMode) {
boolean isNegative = aNumber < 0;
BigDecimal numberAsBigDecimal = new BigDecimal(isNegative ? -aNumber : aNumber);
Threshold threshold = Threshold.thresholdFor(numberAsBigDecimal);
BigDecimal scaledNumber = aNumber == 0 ? numberAsBigDecimal : scaledNumber(
numberAsBigDecimal, aMode);
if (scaledNumber.compareTo(new BigDecimal("1000")) >= 0) {
scaledNumber = scaledNumber(scaledNumber, aMode);
threshold = threshold.getHigherThreshold();
}
String sign = isNegative ? "-" : "";
String printNumber = sign + scaledNumber.stripTrailingZeros().toPlainString()
+ threshold.getSuffix();
// System.out.println("Number: <" + sign + numberAsBigDecimal + ">, rounded: <"
// + sign + scaledNumber + ">, print: <" + printNumber + ">");
return printNumber;
}
}

(取消对 println语句的注释,或者更改为使用您最喜欢的日志程序来查看它在做什么。)

最后,在 数字缩短测试(普通的 JUnit 4)中进行测试:

import static org.junit.Assert.*;


import java.math.BigDecimal;
import java.math.RoundingMode;


import org.junit.Test;


public class NumberShortenerTest {


private static final long[] NUMBERS_FROM_OP = new long[] { 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000 };
private static final String[] EXPECTED_FROM_OP = new String[] { "1k", "5.8k", "10k", "101k", "2m", "7.8m", "92m", "123m" };
private static final String[] EXPECTED_FROM_OP_HALF_UP = new String[] { "1k", "5.8k", "11k", "102k", "2m", "7.8m", "92m", "123m" };
private static final long[] NUMBERS_TO_TEST = new long[] { 1, 500, 999, 1000, 1001, 1009, 1049, 1050, 1099, 1100, 12345, 123456, 999999, 1000000,
1000099, 1000999, 1009999, 1099999, 1100000, 1234567, 999999999, 1000000000, 9123456789L, 123456789123L };
private static final String[] EXPECTED_FROM_TEST = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1k", "1k", "1.1k", "12k", "123k",
"999k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.2m", "999m", "1b", "9.1b", "123b" };
private static final String[] EXPECTED_FROM_TEST_HALF_UP = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1.1k", "1.1k", "1.1k", "12k",
"123k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.1m", "1.2m", "1b", "1b", "9.1b", "123b" };


@Test
public void testThresholdFor() {
assertEquals(Threshold.ZERO, Threshold.thresholdFor(1));
assertEquals(Threshold.ZERO, Threshold.thresholdFor(999));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1000));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1234));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(9999));
assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(999999));
assertEquals(Threshold.MILLION, Threshold.thresholdFor(1000000));
}


@Test
public void testToPrecision() {
RoundingMode mode = RoundingMode.DOWN;
assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
assertEquals(new BigDecimal("1.234"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode).stripTrailingZeros()
.toPlainString());


mode = RoundingMode.HALF_UP;
assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
assertEquals(new BigDecimal("1.235"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
.toPlainString());
assertEquals(new BigDecimal("1000").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode)
.stripTrailingZeros().toPlainString());
}


@Test
public void testNumbersFromOP() {
for (int i = 0; i < NUMBERS_FROM_OP.length; i++) {
assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP[i],
NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP_HALF_UP[i],
NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.HALF_UP));
}
}


@Test
public void testBorders() {
assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.DOWN));
assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.HALF_UP));
for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST[i],
NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST_HALF_UP[i],
NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
}
}


@Test
public void testNegativeBorders() {
for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST[i],
NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.DOWN));
assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST_HALF_UP[i],
NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
}
}
}

如果我错过了一个重要的测试用例,或者期望值应该调整,请在评论中随意指出。

这是一个没有递归的简短实现,只是一个非常小的循环。不与负数工作,但支持所有正的 longLong.MAX_VALUE:

private static final char[] SUFFIXES = {'k', 'm', 'g', 't', 'p', 'e' };


public static String format(long number) {
if(number < 1000) {
// No need to format this
return String.valueOf(number);
}
// Convert to a string
final String string = String.valueOf(number);
// The suffix we're using, 1-based
final int magnitude = (string.length() - 1) / 3;
// The number of digits we must show before the prefix
final int digits = (string.length() - 1) % 3 + 1;


// Build the string
char[] value = new char[4];
for(int i = 0; i < digits; i++) {
value[i] = string.charAt(i);
}
int valueLength = digits;
// Can and should we add a decimal point and an additional number?
if(digits == 1 && string.charAt(1) != '0') {
value[valueLength++] = '.';
value[valueLength++] = string.charAt(1);
}
value[valueLength++] = SUFFIXES[magnitude - 1];
return new String(value, 0, valueLength);
}

产出:

一千
5.8公里
一万
101K
2米
7.8米
9200万
1.23亿美元
9.2 e (这是 Long.MAX_VALUE)

我还做了一些非常简单的基准测试(格式化1000万随机长度) ,它比 Elijah 的实现快得多,比 assylias 的实现稍微快一点。

我的是1137.028毫秒
Elijah 的是2664.396毫秒
1373.473毫秒

下面的代码显示了如何进行简单的扩展。

“魔法”主要在于 makeDecimal函数,对于传入的正确值,它保证输出中的字符数永远不会超过4个。

它首先提取给定除数的全部和十分之一部分,因此,例如,12,345,678的除数为 1,000,000,将给出 whole值为 12tenths值为 3

由此,它可以决定是否只输出整个部分或全部和十分之一部分,使用规则:

  • 如果十分之一部分为零,则只输出整部分和后缀。
  • 如果整部分大于9,只输出整部分和后缀。
  • 否则,输出整部分,十分部分和后缀。

这方面的代码如下:

static private String makeDecimal(long val, long div, String sfx) {
val = val / (div / 10);
long whole = val / 10;
long tenths = val % 10;
if ((tenths == 0) || (whole >= 10))
return String.format("%d%s", whole, sfx);
return String.format("%d.%d%s", whole, tenths, sfx);
}

然后,只需使用正确的值调用 helper 函数,包括一些常量,使开发人员的工作变得更加容易:

static final long THOU =                1000L;
static final long MILL =             1000000L;
static final long BILL =          1000000000L;
static final long TRIL =       1000000000000L;
static final long QUAD =    1000000000000000L;
static final long QUIN = 1000000000000000000L;


static private String Xlat(long val) {
if (val < THOU) return Long.toString(val);
if (val < MILL) return makeDecimal(val, THOU, "k");
if (val < BILL) return makeDecimal(val, MILL, "m");
if (val < TRIL) return makeDecimal(val, BILL, "b");
if (val < QUAD) return makeDecimal(val, TRIL, "t");
if (val < QUIN) return makeDecimal(val, QUAD, "q");
return makeDecimal(val, QUIN, "u");
}

事实上,makeDecimal函数做的工作意味着扩展超越 999,999,999只是一个问题,添加一个额外的行到 Xlat,如此容易,我已经为您做到了。

Xlat中的最终 return不需要条件值,因为在64位有符号长度中可以保存的最大值只有大约9.2乘以二。

但是,如果出于某种奇怪的需求,Oracle 决定添加一个128位 longer类型或一个1024位 damn_long类型,那么您就准备好了: -)


最后,您可以使用一些测试工具来验证功能。

public static void main(String[] args) {
long vals[] = {
999L, 1000L, 5821L, 10500L, 101800L, 2000000L,
7800000L, 92150000L, 123200000L, 999999999L,
1000000000L, 1100000000L, 999999999999L,
1000000000000L, 999999999999999L,
1000000000000000L, 9223372036854775807L
};
for (long val: vals)
System.out.println ("" + val + " -> " + Xlat(val));
}
}

您可以从输出中看到,它为您提供了所需的内容:

999 -> 999
1000 -> 1k
5821 -> 5.8k
10500 -> 10k
101800 -> 101k
2000000 -> 2m
7800000 -> 7.8m
92150000 -> 92m
123200000 -> 123m
999999999 -> 999m
1000000000 -> 1b
1100000000 -> 1.1b
999999999999 -> 999b
1000000000000 -> 1t
999999999999999 -> 999t
1000000000000000 -> 1q
9223372036854775807 -> 9.2u

另外,请注意,向此函数传入负数将导致字符串过长,因为它遵循 < THOU路径)。我觉得没关系,因为你在问题中只提到非负值。

下面的代码片段非常简单、干净,而且完全可以工作:

private static char[] c = new char[]{'K', 'M', 'B', 'T'};
private String formatK(double n, int iteration) {
if (n < 1000) {
// print 999 or 999K
if (iteration <= 0) {
return String.valueOf((long) n);
} else {
return String.format("%d%s", Math.round(n), c[iteration-1]);
}
} else if (n < 10000) {
// Print 9.9K
return String.format("%.1f%s", n/1000, c[iteration]);
} else {
// Increase 1 iteration
return formatK(Math.round(n/1000), iteration+1);
}
}

对于任何想要来的人。这是一个很好的、易于阅读的解决方案,它利用了 Java 的优势。朗。数学图书馆

 public static String formatNumberExample(Number number) {
char[] suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
long numValue = number.longValue();
int value = (int) Math.floor(Math.log10(numValue));
int base = value / 3;
if (value >= 3 && base < suffix.length) {
return new DecimalFormat("~#0.0").format(numValue / Math.pow(10, base * 3)) + suffix[base];
} else {
return new DecimalFormat("#,##0").format(numValue);
}
}

试试这个:

public String Format(Integer number){
String[] suffix = new String[]{"k","m","b","t"};
int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
if (size >= 3){
while (size % 3 != 0) {
size = size - 1;
}
}
double notation = Math.pow(10, size);
String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
return result
}

我的转换大数到小数(2位数)的函数。你可以通过改变 DecimalFormat中的 #.##来改变数字的个数

public String formatValue(float value) {
String arr[] = {"", "K", "M", "B", "T", "P", "E"};
int index = 0;
while ((value / 1000) >= 1) {
value = value / 1000;
index++;
}
DecimalFormat decimalFormat = new DecimalFormat("#.##");
return String.format("%s %s", decimalFormat.format(value), arr[index]);
}

测试

System.out.println(formatValue(100));     //  100
System.out.println(formatValue(1000));    // 1 K
System.out.println(formatValue(10345));   // 10.35 K
System.out.println(formatValue(10012));   // 10.01 K
System.out.println(formatValue(123456));  // 123.46 K
System.out.println(formatValue(4384324)); // 4.38 M
System.out.println(formatValue(10000000)); // 10 M
System.out.println(formatValue(Long.MAX_VALUE)); // 9.22 E

希望能有帮助

这是我的原则,简洁明了。

public static String getRoughNumber(long value) {
if (value <= 999) {
return String.valueOf(value);
}


final String[] units = new String[]{"", "K", "M", "B", "P"};
int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
return new DecimalFormat("#,##0.#").format(value / Math.pow(1000, digitGroups)) + "" + units[digitGroups];


}

使用 Java-12 + ,您可以使用 NumberFormat.getCompactNumberInstance来格式化数字

NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);

然后把它用到 format:

fmt.format(1000)
$5 ==> "1K"


fmt.format(10000000)
$9 ==> "10M"


fmt.format(1000000000)
$11 ==> "1B"
public class NumberToReadableWordFormat {


public static void main(String[] args) {
Integer[] numbers = new Integer[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999,999};
for(int n : numbers) {
System.out.println(n + " => " + coolFormat(n));
}
}


private static String[] c = new String[]{"K", "L", "Cr"};
private static String coolFormat(int n) {
int size = String.valueOf(n).length();
if (size>=4 && size<6) {
int value = (int) Math.pow(10, 1);
double d = (double) Math.round(n/1000.0 * value) / value;
return (double) Math.round(n/1000.0 * value) / value+" "+c[0];
} else if(size>5 && size<8) {
int value = (int) Math.pow(10, 1);
return (double) Math.round(n/100000.0 * value) / value+" "+c[1];
} else if(size>=8) {
int value = (int) Math.pow(10, 1);
return (double) Math.round(n/10000000.0 * value) / value+" "+c[2];
} else {
return n+"";
}
}
}

产出:

1000 => 1.0 K


5821 => 5.8 K


10500 => 10.5 K


101800 => 1.0 L


2000000 => 20.0 L


7800000 => 78.0 L


92150000 => 9.2 Cr


123200000 => 12.3 Cr


9999999 => 100.0 L


999 => 999

这是另一个解决你问题的简单方法。 这么说吧

String abbr="M,K,T,B";

双 yvalue = 某个随机数; 字符串 String = “ # . # #”//小数位置任意

public  String format(Double yvalue, String string,String abbr) {
DecimalFormat df = new DecimalFormat(getnumberformatpattern(string));
if (yvalue < 0) return "-" + format(-yvalue,string,abbr);
double finalvalue= yvalue;
String newnumber="";
          

if (abbr.indexOf("K")>0){
finalvalue= (yvalue / 1e3);
newnumber=df.format(finalvalue) +'K';
}
if (abbr.indexOf("M")>0 ){
if(yvalue>=1e6){
finalvalue= (yvalue / 1e6);
newnumber=df.format(finalvalue) +'M';
};
}
if (abbr.indexOf("B")>0 )
{
if((newnumber.indexOf("M")<0) || yvalue>=1e9){
finalvalue= (yvalue / 1e9);
newnumber=df.format(finalvalue) +'B';                   }
}
if (abbr.indexOf("T")>0 ){
if((newnumber.indexOf("B")<0) || yvalue>=1e12){
finalvalue= (yvalue / 1e12);
newnumber=df.format(finalvalue) +'T';                   }
}
return newnumber;
}

在玛文中心有一个解决方案

<dependency>
<groupId>com.github.bogdanovmn.humanreadablevalues</groupId>
<artifactId>human-readable-values</artifactId>
<version>1.0.1</version>
</dependency>

你可以只获取字节数或秒数的值。你也可以创建你自己的因式分解类。

医生 Https://github.com/bogdanovmn/java-human-readable-values

第二个例子

assertEquals(
"2h 46m 40s",
new SecondsValue(10000).fullString()
);


assertEquals(
"2.8h",
new SecondsValue(10000).shortString()
);

字节的例子

assertEquals(
"9K 784b",
new BytesValue(10000).fullString()
);


assertEquals(
"9.8K",
new BytesValue(10000).shortString()
);

根据输入数字设置除数: 1000,100000,1000000,100000000等。

检查数字的整个部分(没有分数的第一部分) ,如果它的大小是1,然后将输入强制转换为 long + String。 如果大小 > = 2,则除以输入并使用 DecimalFormat 显示所需的小数部分。

可以使用//. setRoundingMode (RoundingMode.DOWN)处理舍入

public static String format(long num) {


String suffix = "", result;
double divisor = 0;


DecimalFormat df = new DecimalFormat("##");
DecimalFormat ds = new DecimalFormat("##.#");
// ds.setRoundingMode(RoundingMode.DOWN);


if ( num >= 1000  && num < 1000000 ) {
divisor = 1000;
suffix = "K";
} else if ( num >= 1000000 && num < 1000000000 ) {
divisor = 1000000;
suffix = "M";
} else if (num >= 1000000000) {
divisor = 1000000000;
suffix = "B";
} else {
System.out.print("The number is Too big > T or TOO small < K");
}


int numlengt = df.format(num / divisor).length();


if (numlengt >= 2) {
result = (long) (num / divisor) + suffix;
} else {
result = ds.format(num / divisor) + suffix;
}
return result;
}
  fun getKLCrValue(input: Long):String{
return if(input.toString().length<4){
input.toString()
}else if(input.toString().length<5)
( ""+getExactValue(input.toString()[0] +"."+ input.toString()[1]) +"K")
else if(input.toString().length<6)
(""+getExactValue(""+input.toString().subSequence(0, 2) +"."+ input.toString()[2]) +"K")
else if(input.toString().length<7)
(""+ getExactValue( input.toString()[0] +"."+input.toString().subSequence(1, 3))+"L")
else if(input.toString().length<8)
(""+ getExactValue( ""+input.toString().subSequence(0, 2)+"."+input.toString().subSequence(2,4))+"L")
else if(input.toString().length<9)
(""+ getExactValue( input.toString()[0] +"."+input.toString().subSequence(1,3))+"Cr")
else
(""+ getExactValue( ""+input.toString().subSequence(0, input.toString().length-7)+"."+input.toString().subSequence( input.toString().length-7, input.toString().length-5))+"cr")


}


private fun getExactValue(value: String): String {
return value.replace(".00", "")
}

只需调用 getKLCrValue (1234)就可以得到所需的输出

产出->

1 -> 1
10 -> 10
12 -> 12
100 -> 100
123 -> 123
1000 -> 1K
1234 -> 1.2K
10000 -> 10K
12345 -> 12.3K
100000 -> 1L
123456 -> 1.23L
1000000 -> 10L
1234567 -> 12.34L
10000000 -> 1cr
12345678 -> 1.23cr
100000000 -> 10cr
123456789 -> 12.34cr
1000000000 -> 100cr
1234567890 -> 123.45cr
10000000000 -> 1000cr
11111111111 -> 1111.11cr