终极短自定义数字格式 - K、M、B、T 等、Q、D、Googol
ultimate short custom number formatting - K, M, B, T, etc., Q, D, Googol
有没有一种方法可以在 google 工作表中自定义格式非常大的数字(两种方式至少高达 10^100):
thousands > K
millions > M
billions > B
trillions > T
etc...
negative quadrillions > Q
decillions > D
或者通过:
- 内部自定义数字格式
- 公式(c的数组公式)
- 类似于 this one 的脚本只是扩展以覆盖更多领域
10000.1 10.0K
100 100.0
1000 1.0K
10000 10.0K
-100000 -100.0K
45646454 45.6M
5654894844216 5.7T
4655454544 4.7B
46546465455511 46.5T
-46546465455511 -46.5T
4654646545551184854556546454454400000000000000000000000000010000000 4.7U
-1000.9999 -1.0K
-100.8989 -100.9
-20.354 -20.4
1.03 1.0
22E+32 2.2D
内部自定义数字格式解决方案:
遗憾的是,google 工作表中的内部格式默认只能处理 3 种类型的数字:
- 阳性(1、2、5、10、...)
- 负数(-3、-9、-7、...)
- 零 (0)
可以对其进行调整以显示自定义格式,例如千 K
、百万 M
和常规小数字:
[>999999]0.0,,"M";[>999]0.0,"K";0
或仅数千 K
、数百万 M
、数十亿 B
[<999950]0.0,"K";[<999950000]0.0,,"M";0.0,,,"B"
或仅负千K
、负百万M
、负十亿B
[>-999950]0.0,"K";[>-999950000]0.0,,"M";0.0,,,"B"
或仅数百万 M
、数十亿 B
、数万亿 T
:
[<999950000]0.0,,"M";[<999950000000]0.0,,,"B";0.0,,,,"T"
或者只有从负百万M
到正百万M
的数字:
[>=999950]0.0,,"M";[<=-999950]0.0,,"M";0.0,"K"
但是你总是只有 3 个插槽可以使用,这意味着你不能像第 4 个那样拥有万亿 type/slot。 fyi,第 4 个插槽存在,但它是为文本保留的。要了解有关 google 工作表中内部格式的更多信息,请参阅:
- https://developers.google.com/sheets/api/guides/formats#meta_instructions
- https://www.benlcollins.com/spreadsheets/google-sheets-custom-number-format/
公式(数组公式)解法:
公式方法更通用...首先,您需要决定要使用的system/standard(美国、欧洲、希腊、国际、非官方等...):
- en.wikipedia.org/wiki/Names_of_large_numbers
- en.wikipedia.org/wiki/Metric_prefix
- simple.wikipedia.org/wiki/Names_for_large_numbers
- home.kpn.nl/vanadovv/BignumbyN
之后尝试:
=INDEX(REGEXREPLACE(IFNA(TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")&VLOOKUP(ABS(A:A)*1, {{10^SEQUENCE(34, 1, 3, 3)},
{"K "; "M "; "B "; "T "; "Qa "; "Qi "; "Sx "; "Sp "; "O "; "N "; "D "; "Ud ";
"Dd "; "Td "; "Qad"; "Qid"; "Sxd"; "Spd"; "Od "; "Nd "; "V "; "Uv "; "Dv "; "Tv ";
"Qav"; "Qiv"; "Sxv"; "Spv"; "Ov "; "Nv "; "Tr "; "Ut "; "Dt "; "Tt "}}, 2, 1),
IF(ISBLANK(A:A),, TEXT(A:A, "0.0 "))), "^0\.0 $", "0 "))
- 适用于正数
- 适用于负数
- 适用于零
- 适用于十进制数
- 适用于数值
- 适用于纯文本数字
- 使用科学记数法
- 适用于空白单元格
- 两种方式都达到 googol 10^104
如果您对它的工作原理感兴趣,请加分...
让我们从虚拟阵列开始{{},{}}
。 SEQUENCE(34, 1, 3, 3)
将在 1
列中为我们提供 34
个数字,从数字 3
开始,步长为 3
个数字:
这些将在 10
的幂 ^
上用作指数
所以我们的虚拟阵列将是:
接下来,我们将它作为 VLOOKUP
的第二个参数插入,我们检查 A 列的 ABS
绝对值(将负值转换为正值)乘以 *1
以防万一A 列的值不是数字。通过 VLOOKUP
我们 return 第二个 2
列,作为第四个参数,我们使用近似 mode 1
从 -999 到 999 的数字在这一点上会故意出错,因此我们稍后可以使用 IFNA
来“修复”我们的错误 IF(A:A=IF(,,),, TEXT(A:A, "#.0 "))
翻译为:if range A:A确实是空的 ISBLANK
什么都不输出,否则使用提供的模式格式化列 #.0
例如。如果单元格 A5 = 空,则输出将为空白单元格...如果 -999 < A5=50 < 999,则输出将为 50.0
最后一部分:
TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")
ABS(A:A)
将负数转换为正数。 INT
删除小数(如果有)。 TEXT(, "0")
将科学计数法 3E+8
转换为常规数字 300000000
。 LEN
计算数字。 -1
更正 base10 表示法。 VLOOKUP
above-constructed number in SEQUENCE
of 35
numbers in 1
column, this time from number 0 ,,
with the step of 3
数字。 return 通过 VLOOKUP
第一个 1
列(例如序列)近似 mode 1
vlookup。在功率 ^
上上升 10
时插入此数字作为指数。并取 A 列中的值并将其除以 above-constructed 数 10
的特定指数的 ^
次幂。最后,将其格式化为 TEXT
as #.0
把丑陋的0.0
变成漂亮的0
我们只用REGEXREPLACE
。并使用 INDEX
而不是更长的 ARRAYFORMULA
.
旁注:要删除尾随空格(这是为了添加很好的对齐方式,哈哈),要么将它们从公式中删除,要么在 INDEX
.
之后使用 TRIM
脚本解决方案:
永远感谢 @TheMaster 的报道
这是其中的一个mod:
/**
* formats various numbers according to the provided short format
* @customfunction
* @param {A1:C100} range a 2D array
* @param {[X1:Y10]} database [optional] a real/virtual 2D array
* where the odd column holds exponent of base 10
* and the even column contains format suffixes
* @param {[5]} value [optional] fix suffix to fixed length
* by padding spaces (only if the second parameter exists)
*/
// examples:
// =CSF(A1:A)
// =CSF(2:2; X5:Y10)
// =CSF(A1:3; G10:J30)
// =CSF(C:C; X:Y; 2) to use custom alignment
// =CSF(C:C; X:Y; 0) to remove alignment
// =INDEX(TRIM(CSF(A:A))) to remove alignment
// =CSF(B10:D30; {3\ "K"; 4\ "TK"}) for non-english sheets
// =CSF(E5, {2, "deci"; 3, "kilo"}) for english sheets
// =INDEX(IF(ISERR(A:A*1); A:A; CSF(A:A))) to return non-numbers
// =INDEX(IF((ISERR(A:A*1))+(ISBLANK(A:A)), A:A, CSF(A:A*1))) enforce mode
function CSF(
range,
database = [
[3, 'K' ], //Thousand
[6, 'M' ], //Million
[9, 'B' ], //Billion
[12, 'T' ], //Trillion
[15, 'Qa' ], //Quadrillion
[18, 'Qi' ], //Quintillion
[21, 'Sx' ], //Sextillion
[24, 'Sp' ], //Septillion
[27, 'O' ], //Octillion
[30, 'N' ], //Nonillion
[33, 'D' ], //Decillion
[36, 'Ud' ], //Undecillion
[39, 'Dd' ], //Duodecillion
[42, 'Td' ], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od' ], //Octodecillion
[60, 'Nd' ], //Novemdecillion
[63, 'V' ], //Vigintillion
[66, 'Uv' ], //Unvigintillion
[69, 'Dv' ], //Duovigintillion
[72, 'Tv' ], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov' ], //Octovigintillion
[90, 'Nv' ], //Novemvigintillion
[93, 'Tr' ], //Trigintillion
[96, 'Ut' ], //Untrigintillion
[99, 'Dt' ], //Duotrigintillion
[100, 'G' ], //Googol
[102, 'Tt' ], //Tretrigintillion or One Hundred Googol
],
value = 3
) {
if (
database[database.length - 1] &&
database[database.length - 1][0] !== 0
) {
database = database.reverse();
database.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(value, ' ');
const decim = 1 // round to decimal places
const separ = 0 // separate number and suffix
const anum = Math.abs(num);
if (num === 0)
return '0' + ' ' + ' '.repeat(separ) + ' '.repeat(decim) + pad3();
if (anum > 0 && anum < 1)
return String(num.toFixed(decim)) + ' '.repeat(separ) + pad3();
for (const [exp, suffix] of database) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(decim)
}${' '.repeat(separ) + pad3(suffix)}`;
}
};
return customFunctionRecurse_(
range, CSF, addSuffix, database, value, true
);
}
function customFunctionRecurse_(
array, mainFunc, subFunc, ...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
旁注 1:此脚本在使用前不需要授权
旁注 2:单元格格式需要设置为自动或数字,否则使用 enforce mode
额外:
- convert numbers into plain text strings/words
- 对于几乎所有实际用途,我们都可以使用 Intl
compact
格式来实现此功能。
/**
* Utility function needed to recurse 2D arrays
*/
function customFunctionRecurse_(
array,
mainFunc,
subFunc,
...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* @customfunction
* @author TheMaster https://whosebug.com/users/8404453
* @param {A1:D2} numArr A 2D array
* @returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
- 但对于极端目的或自定义格式,我们需要使用自定义脚本:
/**
* Formats various numbers according to the provided format
* @customfunction
* @author TheMaster https://whosebug.com/users/8404453
* @param {A1:D2} numArr A 2D array
* @param {X1:Y2} formatArr [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* @param {3} suffixPadLength [optional] Fix suffix to fixed length by padding spaces
* @returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
/**This formatArr array is provided by
* by player0 https://whosebug.com/users/5632629/
* @see
*/
[3, 'K'], //Thousand
[6, 'M'], //Million
[9, 'B'], //Billion
[12, 'T'], //Trillion
[15, 'Qa'], //Quadrillion
[18, 'Qi'], //Quintillion
[21, 'Sx'], //Sextillion
[24, 'Sp'], //Septillion
[27, 'O'], //Octillion
[30, 'N'], //Nonillion
[33, 'D'], //Decillion
[36, 'Ud'], //Undecillion
[39, 'Dd'], //Duodecillion
[42, 'Td'], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od'], //Octodecillion
[60, 'Nd'], //Novemdecillion
[63, 'V'], //Vigintillion
[66, 'Uv'], //Unvigintillion
[69, 'Dv'], //Duovigintillion
[72, 'Tv'], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov'], //Octovigintillion
[90, 'Nv'], //Novemvigintillion
[93, 'Tr'], //Trigintillion
[96, 'Ut'], //Untrigintillion
[99, 'Dt'], //Duotrigintillion
[102, 'G'], //Googol
],
suffixPadLength = 3,
inRecursion = false
) {
if (!inRecursion) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(suffixPadLength, ' '); //pad 3 spaces if necessary
const anum = Math.abs(num);
if (num === 0) return '0' + pad3();
if (anum > 0 && anum < 1) return String(num.toFixed(2)) + pad3();
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${pad3(suffix)}`;
}
};
return customFunctionRecurse_(
numArr,
customFormat,
addSuffix,
formatArr,
suffixPadLength,
true
);
}
用法:
=CUSTOMFORMAT(A1:A5,{{3,"k"};{10,"G"}})
告诉自定义函数使用 k
表示数字>10^3
和 G
表示 10^10
插图:
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
/**
* Utility function needed to map 2D arrays
*/
function customFunctionRecurse_(array, mainFunc, subFunc, extraArgToMainFunc) {
if (Array.isArray(array))
return array.map((e) => mainFunc(e, extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* @customfunction
* @param {A1:D2} A 2D array
* @returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
/**
* Formats various numbers according to the provided format
* @customfunction
* @param {A1:D2} A 2D array
* @param {X1:Y2=} [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* @returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
//sample byte => kb formatting
[3, 'kb'],
[6, 'mb'],
[9, 'gb'],
[12, 'tb'],
]
) {
//console.log({ numArr, formatArr });
if (
formatArr[formatArr.length - 1] &&
formatArr[formatArr.length - 1][0] !== 0
) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = (num) => {
const anum = Math.abs(num);
if (num === 0) return '0.00';
if (anum > 0 && anum < 1) return String(num.toFixed(2));
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${suffix}`;
}
};
return customFunctionRecurse_(numArr, customFormat, addSuffix, formatArr);
}
console.log(
customFormat([
[
0,
1000,
153,
12883255,
235688235123,
88555552233355888,
-86555,
0.8523588055,
Math.pow(10, 15),
],
])
);
<!-- https://meta.whosebug.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
有时我们在处理核物理时需要缩短时间,所以是这样的:
=INDEX(IF(ISBLANK(A2:A),,TEXT(TRUNC(TEXT(IF(A2:A*1<1,
TEXT(A2:A*1, "0."&REPT(0, 30))*VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3)}),
{0; 10^SORT(SEQUENCE(9, 1, 3, 3), 1,)}}, 2, 1), TEXT(A2:A*1, REPT(0, 30))/
VLOOKUP(A2:A*1, TEXT({1; 60; 3600; 86400; 31536000; 31536000*10^SEQUENCE(8, 1, 3, 3)},
{"#", "#"})*1, 2, 1)), "0."&REPT("0", 30)), 3), "0.000")&" "&
VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3);
{1; 60; 3600; 86400; 31536000}; 31536000*10^SEQUENCE(8, 1, 3, 3)}), FLATTEN(SPLIT(
"s ys zs as fs ps ns μs ms s m h d y ky My Gy Ty Py Ey Zy Yy", " ",,))}, 2, 1)))
这是利用国际单位制从秒到缩写的简单转换,其中:
in seconds
____________________________________
ys = yoctosecond = 0.000000000000000000000001
zs = zeptosecond = 0.000000000000000000001
as = attosecond = 0.000000000000000001
fs = femtosecond = 0.000000000000001
ps = pikosecond = 0.000000000001
ns = nanosecond = 0.000000001
μs = microsecond = 0.000001
ms = millisecond = 0.001
s = second = 1
m = minute = 60
h = hour = 3600
d = day = 86400
y = year = 31536000
ky = kiloyear = 31536000000
My = megayear = 31536000000000
Gy = gigayear = 31536000000000000
Ty = terayear = 31536000000000000000
Py = petayear = 31536000000000000000000
Ey = exayear = 31536000000000000000000000
Zy = zettayear = 31536000000000000000000000000
Yy = yottayear = 31536000000000000000000000000000
有没有一种方法可以在 google 工作表中自定义格式非常大的数字(两种方式至少高达 10^100):
thousands > K
millions > M
billions > B
trillions > T
etc...
negative quadrillions > Q
decillions > D
或者通过:
- 内部自定义数字格式
- 公式(c的数组公式)
- 类似于 this one 的脚本只是扩展以覆盖更多领域
10000.1 10.0K
100 100.0
1000 1.0K
10000 10.0K
-100000 -100.0K
45646454 45.6M
5654894844216 5.7T
4655454544 4.7B
46546465455511 46.5T
-46546465455511 -46.5T
4654646545551184854556546454454400000000000000000000000000010000000 4.7U
-1000.9999 -1.0K
-100.8989 -100.9
-20.354 -20.4
1.03 1.0
22E+32 2.2D
内部自定义数字格式解决方案:
遗憾的是,google 工作表中的内部格式默认只能处理 3 种类型的数字:
- 阳性(1、2、5、10、...)
- 负数(-3、-9、-7、...)
- 零 (0)
可以对其进行调整以显示自定义格式,例如千 K
、百万 M
和常规小数字:
[>999999]0.0,,"M";[>999]0.0,"K";0
或仅数千 K
、数百万 M
、数十亿 B
[<999950]0.0,"K";[<999950000]0.0,,"M";0.0,,,"B"
或仅负千K
、负百万M
、负十亿B
[>-999950]0.0,"K";[>-999950000]0.0,,"M";0.0,,,"B"
或仅数百万 M
、数十亿 B
、数万亿 T
:
[<999950000]0.0,,"M";[<999950000000]0.0,,,"B";0.0,,,,"T"
或者只有从负百万M
到正百万M
的数字:
[>=999950]0.0,,"M";[<=-999950]0.0,,"M";0.0,"K"
但是你总是只有 3 个插槽可以使用,这意味着你不能像第 4 个那样拥有万亿 type/slot。 fyi,第 4 个插槽存在,但它是为文本保留的。要了解有关 google 工作表中内部格式的更多信息,请参阅:
- https://developers.google.com/sheets/api/guides/formats#meta_instructions
- https://www.benlcollins.com/spreadsheets/google-sheets-custom-number-format/
公式(数组公式)解法:
公式方法更通用...首先,您需要决定要使用的system/standard(美国、欧洲、希腊、国际、非官方等...):
- en.wikipedia.org/wiki/Names_of_large_numbers
- en.wikipedia.org/wiki/Metric_prefix
- simple.wikipedia.org/wiki/Names_for_large_numbers
- home.kpn.nl/vanadovv/BignumbyN
之后尝试:
=INDEX(REGEXREPLACE(IFNA(TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")&VLOOKUP(ABS(A:A)*1, {{10^SEQUENCE(34, 1, 3, 3)},
{"K "; "M "; "B "; "T "; "Qa "; "Qi "; "Sx "; "Sp "; "O "; "N "; "D "; "Ud ";
"Dd "; "Td "; "Qad"; "Qid"; "Sxd"; "Spd"; "Od "; "Nd "; "V "; "Uv "; "Dv "; "Tv ";
"Qav"; "Qiv"; "Sxv"; "Spv"; "Ov "; "Nv "; "Tr "; "Ut "; "Dt "; "Tt "}}, 2, 1),
IF(ISBLANK(A:A),, TEXT(A:A, "0.0 "))), "^0\.0 $", "0 "))
- 适用于正数
- 适用于负数
- 适用于零
- 适用于十进制数
- 适用于数值
- 适用于纯文本数字
- 使用科学记数法
- 适用于空白单元格
- 两种方式都达到 googol 10^104
如果您对它的工作原理感兴趣,请加分...
让我们从虚拟阵列开始{{},{}}
。 SEQUENCE(34, 1, 3, 3)
将在 1
列中为我们提供 34
个数字,从数字 3
开始,步长为 3
个数字:
这些将在 10
的幂 ^
所以我们的虚拟阵列将是:
接下来,我们将它作为 VLOOKUP
的第二个参数插入,我们检查 A 列的 ABS
绝对值(将负值转换为正值)乘以 *1
以防万一A 列的值不是数字。通过 VLOOKUP
我们 return 第二个 2
列,作为第四个参数,我们使用近似 mode 1
从 -999 到 999 的数字在这一点上会故意出错,因此我们稍后可以使用 IFNA
来“修复”我们的错误 IF(A:A=IF(,,),, TEXT(A:A, "#.0 "))
翻译为:if range A:A确实是空的 ISBLANK
什么都不输出,否则使用提供的模式格式化列 #.0
例如。如果单元格 A5 = 空,则输出将为空白单元格...如果 -999 < A5=50 < 999,则输出将为 50.0
最后一部分:
TEXT(A:A/10^(VLOOKUP(LEN(TEXT(INT(ABS(A:A)), "0"))-1,
SEQUENCE(35, 1,, 3), 1, 1)), "#.0")
ABS(A:A)
将负数转换为正数。 INT
删除小数(如果有)。 TEXT(, "0")
将科学计数法 3E+8
转换为常规数字 300000000
。 LEN
计算数字。 -1
更正 base10 表示法。 VLOOKUP
above-constructed number in SEQUENCE
of 35
numbers in 1
column, this time from number 0 ,,
with the step of 3
数字。 return 通过 VLOOKUP
第一个 1
列(例如序列)近似 mode 1
vlookup。在功率 ^
上上升 10
时插入此数字作为指数。并取 A 列中的值并将其除以 above-constructed 数 10
的特定指数的 ^
次幂。最后,将其格式化为 TEXT
as #.0
把丑陋的0.0
变成漂亮的0
我们只用REGEXREPLACE
。并使用 INDEX
而不是更长的 ARRAYFORMULA
.
旁注:要删除尾随空格(这是为了添加很好的对齐方式,哈哈),要么将它们从公式中删除,要么在 INDEX
.
TRIM
脚本解决方案:
永远感谢 @TheMaster 的报道
这是其中的一个mod:
/**
* formats various numbers according to the provided short format
* @customfunction
* @param {A1:C100} range a 2D array
* @param {[X1:Y10]} database [optional] a real/virtual 2D array
* where the odd column holds exponent of base 10
* and the even column contains format suffixes
* @param {[5]} value [optional] fix suffix to fixed length
* by padding spaces (only if the second parameter exists)
*/
// examples:
// =CSF(A1:A)
// =CSF(2:2; X5:Y10)
// =CSF(A1:3; G10:J30)
// =CSF(C:C; X:Y; 2) to use custom alignment
// =CSF(C:C; X:Y; 0) to remove alignment
// =INDEX(TRIM(CSF(A:A))) to remove alignment
// =CSF(B10:D30; {3\ "K"; 4\ "TK"}) for non-english sheets
// =CSF(E5, {2, "deci"; 3, "kilo"}) for english sheets
// =INDEX(IF(ISERR(A:A*1); A:A; CSF(A:A))) to return non-numbers
// =INDEX(IF((ISERR(A:A*1))+(ISBLANK(A:A)), A:A, CSF(A:A*1))) enforce mode
function CSF(
range,
database = [
[3, 'K' ], //Thousand
[6, 'M' ], //Million
[9, 'B' ], //Billion
[12, 'T' ], //Trillion
[15, 'Qa' ], //Quadrillion
[18, 'Qi' ], //Quintillion
[21, 'Sx' ], //Sextillion
[24, 'Sp' ], //Septillion
[27, 'O' ], //Octillion
[30, 'N' ], //Nonillion
[33, 'D' ], //Decillion
[36, 'Ud' ], //Undecillion
[39, 'Dd' ], //Duodecillion
[42, 'Td' ], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od' ], //Octodecillion
[60, 'Nd' ], //Novemdecillion
[63, 'V' ], //Vigintillion
[66, 'Uv' ], //Unvigintillion
[69, 'Dv' ], //Duovigintillion
[72, 'Tv' ], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov' ], //Octovigintillion
[90, 'Nv' ], //Novemvigintillion
[93, 'Tr' ], //Trigintillion
[96, 'Ut' ], //Untrigintillion
[99, 'Dt' ], //Duotrigintillion
[100, 'G' ], //Googol
[102, 'Tt' ], //Tretrigintillion or One Hundred Googol
],
value = 3
) {
if (
database[database.length - 1] &&
database[database.length - 1][0] !== 0
) {
database = database.reverse();
database.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(value, ' ');
const decim = 1 // round to decimal places
const separ = 0 // separate number and suffix
const anum = Math.abs(num);
if (num === 0)
return '0' + ' ' + ' '.repeat(separ) + ' '.repeat(decim) + pad3();
if (anum > 0 && anum < 1)
return String(num.toFixed(decim)) + ' '.repeat(separ) + pad3();
for (const [exp, suffix] of database) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(decim)
}${' '.repeat(separ) + pad3(suffix)}`;
}
};
return customFunctionRecurse_(
range, CSF, addSuffix, database, value, true
);
}
function customFunctionRecurse_(
array, mainFunc, subFunc, ...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
旁注 1:此脚本在使用前不需要授权
旁注 2:单元格格式需要设置为自动或数字,否则使用 enforce mode
额外:
- convert numbers into plain text strings/words
- 对于几乎所有实际用途,我们都可以使用 Intl
compact
格式来实现此功能。
/**
* Utility function needed to recurse 2D arrays
*/
function customFunctionRecurse_(
array,
mainFunc,
subFunc,
...extraArgToMainFunc
) {
if (Array.isArray(array))
return array.map(e => mainFunc(e, ...extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* @customfunction
* @author TheMaster https://whosebug.com/users/8404453
* @param {A1:D2} numArr A 2D array
* @returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
- 但对于极端目的或自定义格式,我们需要使用自定义脚本:
/**
* Formats various numbers according to the provided format
* @customfunction
* @author TheMaster https://whosebug.com/users/8404453
* @param {A1:D2} numArr A 2D array
* @param {X1:Y2} formatArr [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* @param {3} suffixPadLength [optional] Fix suffix to fixed length by padding spaces
* @returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
/**This formatArr array is provided by
* by player0 https://whosebug.com/users/5632629/
* @see
*/
[3, 'K'], //Thousand
[6, 'M'], //Million
[9, 'B'], //Billion
[12, 'T'], //Trillion
[15, 'Qa'], //Quadrillion
[18, 'Qi'], //Quintillion
[21, 'Sx'], //Sextillion
[24, 'Sp'], //Septillion
[27, 'O'], //Octillion
[30, 'N'], //Nonillion
[33, 'D'], //Decillion
[36, 'Ud'], //Undecillion
[39, 'Dd'], //Duodecillion
[42, 'Td'], //Tredecillion
[45, 'Qad'], //Quattuordecillion
[48, 'Qid'], //Quindecillion
[51, 'Sxd'], //Sexdecillion
[54, 'Spd'], //Septendecillion
[57, 'Od'], //Octodecillion
[60, 'Nd'], //Novemdecillion
[63, 'V'], //Vigintillion
[66, 'Uv'], //Unvigintillion
[69, 'Dv'], //Duovigintillion
[72, 'Tv'], //Trevigintillion
[75, 'Qav'], //Quattuorvigintillion
[78, 'Qiv'], //Quinvigintillion
[81, 'Sxv'], //Sexvigintillion
[84, 'Spv'], //Septenvigintillion
[87, 'Ov'], //Octovigintillion
[90, 'Nv'], //Novemvigintillion
[93, 'Tr'], //Trigintillion
[96, 'Ut'], //Untrigintillion
[99, 'Dt'], //Duotrigintillion
[102, 'G'], //Googol
],
suffixPadLength = 3,
inRecursion = false
) {
if (!inRecursion) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = num => {
const pad3 = (str = '') => str.padEnd(suffixPadLength, ' '); //pad 3 spaces if necessary
const anum = Math.abs(num);
if (num === 0) return '0' + pad3();
if (anum > 0 && anum < 1) return String(num.toFixed(2)) + pad3();
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${pad3(suffix)}`;
}
};
return customFunctionRecurse_(
numArr,
customFormat,
addSuffix,
formatArr,
suffixPadLength,
true
);
}
用法:
=CUSTOMFORMAT(A1:A5,{{3,"k"};{10,"G"}})
告诉自定义函数使用
k
表示数字>10^3
和G
表示10^10
插图:
/*<ignore>*/console.config({maximize:true,timeStamps:false,autoScroll:false});/*</ignore>*/
/**
* Utility function needed to map 2D arrays
*/
function customFunctionRecurse_(array, mainFunc, subFunc, extraArgToMainFunc) {
if (Array.isArray(array))
return array.map((e) => mainFunc(e, extraArgToMainFunc));
else return subFunc(array);
}
/**
* Simple custom formating function using Intl
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
* @customfunction
* @param {A1:D2} A 2D array
* @returns {String[][]}Compact Intl formatted 2D array
*/
function format(numArr) {
const cIntl = new Intl.NumberFormat('en-GB', {
notation: 'compact',
compactDisplay: 'short',
});
return customFunctionRecurse_(numArr, format, (num) => cIntl.format(num));
}
/**
* Formats various numbers according to the provided format
* @customfunction
* @param {A1:D2} A 2D array
* @param {X1:Y2=} [optional] A format 2D real/virtual array
* with base 10 power -> suffix mapping
* eg: X1:3 Y1:K represents numbers > 10^3 should have a K suffix
* @returns {String[][]} Formatted 2D array
*/
function customFormat(
numArr,
formatArr = [
//sample byte => kb formatting
[3, 'kb'],
[6, 'mb'],
[9, 'gb'],
[12, 'tb'],
]
) {
//console.log({ numArr, formatArr });
if (
formatArr[formatArr.length - 1] &&
formatArr[formatArr.length - 1][0] !== 0
) {
formatArr = formatArr.reverse();
formatArr.push([0, '']);
}
const addSuffix = (num) => {
const anum = Math.abs(num);
if (num === 0) return '0.00';
if (anum > 0 && anum < 1) return String(num.toFixed(2));
for (const [exp, suffix] of formatArr) {
if (anum >= Math.pow(10, exp))
return `${(num / Math.pow(10, exp)).toFixed(2)}${suffix}`;
}
};
return customFunctionRecurse_(numArr, customFormat, addSuffix, formatArr);
}
console.log(
customFormat([
[
0,
1000,
153,
12883255,
235688235123,
88555552233355888,
-86555,
0.8523588055,
Math.pow(10, 15),
],
])
);
<!-- https://meta.whosebug.com/a/375985/ --> <script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
有时我们在处理核物理时需要缩短时间,所以是这样的:
=INDEX(IF(ISBLANK(A2:A),,TEXT(TRUNC(TEXT(IF(A2:A*1<1,
TEXT(A2:A*1, "0."&REPT(0, 30))*VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3)}),
{0; 10^SORT(SEQUENCE(9, 1, 3, 3), 1,)}}, 2, 1), TEXT(A2:A*1, REPT(0, 30))/
VLOOKUP(A2:A*1, TEXT({1; 60; 3600; 86400; 31536000; 31536000*10^SEQUENCE(8, 1, 3, 3)},
{"#", "#"})*1, 2, 1)), "0."&REPT("0", 30)), 3), "0.000")&" "&
VLOOKUP(A2:A*1, {SORT({0; 1/10^SEQUENCE(9, 1, 3, 3);
{1; 60; 3600; 86400; 31536000}; 31536000*10^SEQUENCE(8, 1, 3, 3)}), FLATTEN(SPLIT(
"s ys zs as fs ps ns μs ms s m h d y ky My Gy Ty Py Ey Zy Yy", " ",,))}, 2, 1)))
这是利用国际单位制从秒到缩写的简单转换,其中:
in seconds
____________________________________
ys = yoctosecond = 0.000000000000000000000001
zs = zeptosecond = 0.000000000000000000001
as = attosecond = 0.000000000000000001
fs = femtosecond = 0.000000000000001
ps = pikosecond = 0.000000000001
ns = nanosecond = 0.000000001
μs = microsecond = 0.000001
ms = millisecond = 0.001
s = second = 1
m = minute = 60
h = hour = 3600
d = day = 86400
y = year = 31536000
ky = kiloyear = 31536000000
My = megayear = 31536000000000
Gy = gigayear = 31536000000000000
Ty = terayear = 31536000000000000000
Py = petayear = 31536000000000000000000
Ey = exayear = 31536000000000000000000000
Zy = zettayear = 31536000000000000000000000000
Yy = yottayear = 31536000000000000000000000000000