数字格式化的 js 库

​Numeral.js​​​,是一个用于​​格式化数字​​​和​​处理数字​​的 js 库。

Tip:目前 Star 有 ​​9.2k​​​,5年以前就没有在更新。其​​文档​​​写得不很清晰,比如它提供了多语言,但如何切换成中文,怎么使用却没有说,对于某些问题(​​abbreviations 报错​​)笔者只有从源码、更新日志和 Issues 中寻找答案。

使用它

node 中通过 npm 安装即可:

PS E:\react-project> npm i numeral

Tip:也可以在浏览器中直接通过 src 的方式使用。

创建实例

通过 ​​numeral()​​ 创建一个实例:

var myNumeral = numeral(1000);
var value = myNumeral.value();
// value 1000
console.log('value', value)

感觉好鸡肋,但可以​​取消格式化​​​。比如将 ​​1,000​​​ 处理成 ​​1000​​:

var myNumeral2 = numeral('1,000');
var value2 = myNumeral2.value();
// value2 1000
console.log('value2', value2)

格式化

这部分是我们最关心的。比如笔者的需求有:

  • 将后台的字节数根据数值大小自动转为​​KB​​​、​​MB​​​、​​GB​​等对应的单位
  • 数字太长,显示区域有限,比如将​​123456789​​​ 转为​​123.5m​​​ 或​​123.5百万​

format()

通过 ​​format()​​​ 可以将 ​​1000​​​ 格式化成 ​​1,000​​​,将 ​​123456789​​​ 格式化成 ​​123,456,789​​。请看示例:

var number = numeral(1000).format('0,0');
// number: 1,000
console.log('number: ', number);
var number2 = numeral(123456789).format('0,0');
// number2: 123,456,789
console.log('number2: ', number2);
// 四舍五入
var number3 = numeral(1.93).format('0,0');
// number3: 2
console.log('number3: ', number3);
// 四舍五入
var number4 = numeral(1.23).format('0,0');
// number4: 1
console.log('number4: ', number4);

Tip:上面我们用了 ​​0,0​​​ 这种格式,其他格式请直接看 ​​numeral.js​​:

// node_modules\numeral\tests\numeral.js
describe('Format', function() {
it('should format to a number', function() {
var tests = [
[0, null, '0'],
[0, '0.00', '0.00'],
[null, null, '0'],
[NaN, '0.0', '0.0'],
[1.23,'0,0','1'],
[10000,'0,0.0000','10,000.0000'],
[10000.23,'0,0','10,000'],
[-10000,'0,0.0','-10,000.0'],
[10000.1234,'0.000','10000.123'],
[10000,'0[.]00','10000'],
[10000.1,'0[.]00','10000.10'],
[10000.123,'0[.]00','10000.12'],
[10000.456,'0[.]00','10000.46'],
[10000.001,'0[.]00','10000'],
[10000.45,'0[.]00[0]','10000.45'],
[10000.456,'0[.]00[0]','10000.456'],
[10000,'(0,0.0000)','10,000.0000'],
[-10000,'(0,0.0000)','(10,000.0000)'],
[-12300,'+0,0.0000','-12,300.0000'],
[1230,'+0,0','+1,230'],
[1230,'-0,0','1,230'],
[-1230,'-0,0','-1,230'],
[-1230.4,'0,0.0+','1,230.4-'],
[-1230.4,'0,0.0-','1,230.4-'],
[1230.4,'0,0.0-','1,230.4'],
[100.78, '0', '101'],
[100.28, '0', '100'],
[1.932,'0.0','1.9'],
[1.9687,'0','2'],
[1.9687,'0.0','2.0'],
[-0.23,'.00','-.23'],
[-0.23,'(.00)','(.23)'],
[0.23,'0.00000','0.23000'],
[0.67,'0.0[0000]','0.67'],
[3162.63,'0.0[00000000000000]','3162.63'],
[1.99,'0.[0]','2'],
[1.0501,'0.00[0]','1.05'],
[1.005,'0.00','1.01'],
// leading zero
[0, '00.0', '00.0'],
[0.23, '000.[00]', '000.23'],
[4, '000', '004'],
[10, '00000', '00010'],
[1000, '000,0', '1,000'],
[1000, '00000,0', '01,000'],
[1000, '0000000,0', '0,001,000'],
// abbreviations
[2000000000,'0.0a','2.0b'],
[1230974,'0.0a','1.2m'],
[1460,'0a','1k'],
[-104000,'0 a','-104 k'],
[999950,'0.0a','1.0m'],
[999999999,'0a','1b'],
// forced abbreviations
[-5444333222111, '0,0 ak', '-5,444,333,222 k'],
[5444333222111, '0,0 am', '5,444,333 m'],
[-5444333222111, '0,0 ab', '-5,444 b'],
[-5444333222111, '0,0 at', '-5 t'],
[123456, '0.0[0] ak', '123.46 k'],
[150,'0.0 ak','0.2 k']
],
i,
n,
output;

for (i = 0; i < tests.length; i++) {
n = numeral(tests[i][0]);
output = n.format(tests[i][1]);

expect(output).to.equal(tests[i][2]);

expect(typeof output).to.equal('string');
}
});
});

字节转换

比如将 ​​1024​​​ 转为 ​​1KB​​​,将 ​​1024*1024​​​ 转为 ​​1MB​​。将请看示例:

PS D:\spug-study> node 
Welcome to Node.js v16.14.2.
Type ".help" for more information.
> let numeral = require('numeral')
undefined
> numeral(1024).format('0b')
'1KB'
> numeral(1024*1024).format('0b')
'1MB'
> numeral(1024*1024*1024).format('0b')
'1GB'
> numeral(1024*1024*1024*1024).format('0b')
'1TB'
> numeral(1024*1024*1024*1024*32).format('0b')
'35TB'
>

Tip:笔者直接在 node 环境下运行。更多格式化语法请看 ​​bytes.js​​ 文件。

// node_modules\numeral\tests\formats\bytes.js
it('should format to bytes', function() {
var decimal = 1000;
var binary = 1024;
var tests = [
[0,'0b','0B'],
[null,'0 b','0 B'],
[100,'0b','100B'],
[binary * 2,'0 ib','2 KiB'],
[Math.pow(binary, 2) * 5,'0ib','5MiB'],
[Math.pow(binary, 3) * 7.343,'0.[0] ib','7.3 GiB'],
[Math.pow(binary, 4) * 3.1536544,'0.000ib','3.154TiB'],
[Math.pow(binary, 5) * 2.953454534534,'0ib','3PiB'],
[decimal * 2,'0 b','2 KB'],
[Math.pow(decimal, 2) * 5,'0b','5MB'],
[Math.pow(decimal, 3) * 7.343,'0.[0] b','7.3 GB'],
[Math.pow(decimal, 4) * 3.1536544,'0.000b','3.154TB'],
[Math.pow(decimal, 5) * 2.953454534534,'0b','3PB']
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).format(tests[i][1])).to.equal(tests[i][2]);
}
});
字节转数字

比如可以将 ​​1KB​​​ 转为数字,但结果只是 ​​1000​​​,如果要 ​​1024​​​,需要使用 ​​1 KiB​​。请看示例:

> numeral('1KB').value()
1000
> numeral('1 KiB').value()
1024
> numeral('1MB').value()
1000000

Tip:有关​​字节反解析​​​的更多介绍请看 ​​bytes.js​​。

// node_modules\numeral\tests\formats\bytes.js
it('should unformat to number', function() {
var decimal = 1000;
var binary = 1024;
var tests = [
['0B', 0],
['0 B', 0],
['100B', 100],
['2 KiB', binary * 2],
['5MiB', Math.pow(binary, 2) * 5],
['7.3 GiB', Math.pow(binary, 3) * 7.3],
['3.154TiB', Math.pow(binary, 4) * 3.154],
['3PiB', Math.pow(binary, 5) * 3],
['2 KB', decimal * 2],
['5MB', Math.pow(decimal, 2) * 5],
['7.3 GB', Math.pow(decimal, 3) * 7.3],
['3.154TB', Math.pow(decimal, 4) * 3.154],
['3PB', Math.pow(decimal, 5) * 3]
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).value()).to.equal(tests[i][1]);
}
});

时间转换转化

将数字(秒)转为时间形式。请看示例:

> numeral(1).format('00:00:00')
'0:00:01'
> numeral(60).format('00:00:00')
'0:01:00'
> numeral(60*60).format('00:00:00')
'1:00:00'

百分比转化

请看示例:

> numeral(0.974878234).format('0.000%')
'97.488%'
> numeral(0).format('0%')
'0%'
> numeral(1).format('0%')
'100%'

Tip:更多介绍请看 ​​node_modules\numeral\tests\formats\percentage.js​​。

货币转化

请看示例:

> numeral(1000.234).format('$0,0.00')
'$1,000.23'

Tip:更多用法请看 ​​currency.js​​。

// node_modules\numeral\tests\formats\currency.js
describe('Currency', function() {
after(function() {
numeral.reset();
});

it('should format to currency', function() {
var tests = [
[0,'$0.00','$0.00'],
[null,'$0.00','$0.00'],
[0.99,'$0,0.00','$0.99'],
[1000.234,'$0,0.00','$1,000.23'],
[1001,'$ 0,0.[00]','$ 1,001'],
[1000.234,'0,0.00 $','1,000.23 $'],
[-1000.234,'0,0.00 $','-1,000.23 $'],
[-1000.234,'($0,0)','($1,000)'],
[-1000.234,'(0,0$)','(1,000$)'],
[-1000.234,'(0,0 $)','(1,000 $)'],
[-1000.234,'$0.00','-$1000.23'],
[-1000.234,'$ 0.00','-$ 1000.23'],
[1230974,'($0.00 a)','$1.23 m'],
[-1000.234,'$ (0,0)','$ (1,000)'],
[-1000.234,'$(0,0)','$(1,000)'],
[-1000.234,'$ (0,0.00)','$ (1,000.23)'],
[-1000.234,'$(0,0.00)','$(1,000.23)'],
[-1000.238,'$(0,0.00)','$(1,000.24)'],
[-1000.234,'$-0,0','$-1,000'],
[-1000.234,'$ -0,0','$ -1,000'],
[1000.234,'$ (0,0)','$ 1,000'],
[1000.234,'$(0,0)','$1,000'],
[1000.234,'$ (0,0.00)','$ 1,000.23'],
[1000.234,'$(0,0.00)','$1,000.23'],
[1000.238,'$(0,0.00)','$1,000.24'],
[1000.234,'$-0,0','$1,000'],
[1000.234,'$ -0,0','$ 1,000']
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).format(tests[i][1])).to.equal(tests[i][2]);
}
});

it('should unformat to currency', function() {
var tests = [
['$0.00', 0],
['$0.99', 0.99],
['$1,000.23', 1000.23],
['1,000.23 $', 1000.23],
['($1,000)', -1000],
['-1,000$', -1000],
['$1.23 m', 1230000],
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).value()).to.equal(tests[i][1]);
}
});
});

指数转化

请看示例:

> numeral(77777777.1234).format('0.0e+0')
'7.8e+7'

Tip:更多用法请看 ​​exponential.js​​。

// node_modules\numeral\tests\formats\exponential.js
it('should format to exponential notation', function() {
var tests = [
[0,'0e+0','0e+0'],
[null,'0e+0','0e+0'],
[1,'0e+0','1e+0'],
[77.1234,'0.0e+0','7.7e+1'],
[0.000000771234,'0.0e-0','7.7e-7'],
[-0.000000771234,'0.00e-0','-7.71e-7'],
[77.1234,'0.000e+0','7.712e+1'],
[-1000830298,'0.0[000]e+0','-1.0008e+9']
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).format(tests[i][1])).to.equal(tests[i][2]);
}
});

比特率转化

比特率,是指单位时间内传送的比特(bit)数,单位为bps(bit per second)。

> numeral(.0056).format('0 BPS')
'56 BPS'

Tip:更多用法请看 ​​bps.js​​:

// node_modules\numeral\tests\formats\bps.js
it('should format to bps', function() {
var tests = [
[0,'0 BPS','0 BPS'],
[0.0001, '0 BPS', '1 BPS'],
[.0056, '0 BPS', '56 BPS'],
[.25, '0BPS', '2500BPS'],
[.000001, '0.00 BPS', '0.01 BPS']
],
i;

for (i = 0; i < tests.length; i++) {
expect(numeral(tests[i][0]).format(tests[i][1])).to.equal(tests[i][2]);
}
});

四则运算

numeral 提供​​加减乘除​​​四则运算的方法,例如 ​​1000​​​ 加 ​​10​​​ 等于 ​​1010​​。请看示例:

> numeral(1000).add(10).value()
1010

Tip:更多介绍请看 ​​numeral.js​​。

// node_modules\numeral\tests\numeral.js
describe('Manipulate', function() {
// 加法
describe('Add', function() {
it('should add', function() {
var tests = [
[1000,10,1010],
[0.5,3,3.5],
[-100,200,100],
[0.1,0.2,0.3],
[0.28,0.01,0.29],
[0.289999,0.000001,0.29],
[0.29,0.01,0.3]
],
num;

for (var i = 0; i < tests.length; i++) {
num = numeral(tests[i][0]);

num.add(tests[i][1]);

expect(num.value()).to.equal(tests[i][2]);
}
});
});

// 减法
describe('Subtract', function() {
it('should subtract', function() {
var tests = [
[1000,10,990],
[0.5,3,-2.5],
[-100,200,-300],
[0.3,0.1,0.2],
[0.28,0.01,0.27],
[0.29,0.01,0.28]
],
num;

for (var i = 0; i < tests.length; i++) {
num = numeral(tests[i][0]);

num.subtract(tests[i][1]);

expect(num.value()).to.equal(tests[i][2]);
}
});
});

// 乘法
describe('Multiply', function() {
it('should multiply', function() {
var tests = [
[1000,10,10000],
[0.5,3,1.5],
[-100,200,-20000],
[0.1,0.2,0.02],
[0.28,0.01,0.0028],
[0.29,0.01,0.0029],
[0.00000231,10000000,23.1]
],
num;

for (var i = 0; i < tests.length; i++) {
num = numeral(tests[i][0]);

num.multiply(tests[i][1]);

expect(num.value()).to.equal(tests[i][2]);
}
});
});

// 除法
describe('Divide', function() {
it('should divide', function() {
var tests = [
[1000,10,100],
[0.5,3,0.16666666666666666],
[-100,200,-0.5],
[5.3,0.1,53],
[0.28,0.01,28],
[0.29,0.01,29]
],
num;

for (var i = 0; i < tests.length; i++) {
num = numeral(tests[i][0]);

num.divide(tests[i][1]);

expect(num.value()).to.equal(tests[i][2]);
}
});
});

// 差值。例如 1000 和 10 相差 990。
describe('Difference', function() {
it('should find a difference', function() {
var tests = [
[1000,10,990],
[0.5,3,2.5],
[-100,200,300],
[0.3,0.2,0.1],
[0.28,0.01,0.27],
[0.29,0.01,0.28]
],
num;

for (var i = 0; i < tests.length; i++) {
num = numeral(tests[i][0]);

expect(num.difference(tests[i][1])).to.equal(tests[i][2]);
}
});
});

// 四舍五入。
describe('Rounding', function() {
it('should format with rounding', function() {
var tests = [
// value, format string, expected w/ floor, expected w/ ceil
[2280002, '0.00a', '2.28m', '2.29m'],
[10000.23,'0,0','10,000', '10,001'],
[1000.234,'0,0.00','1,000.23', '1,000.24'],
[0.97487823,'0.000','0.974','0.975'],
[-0.433,'0.0','-0.5', '-0.4']
],
i;

for (i = 0; i < tests.length; i++) {
// floor
expect(numeral(tests[i][0]).format(tests[i][1], Math.floor)).to.equal(tests[i][2]);

// ceil
expect(numeral(tests[i][0]).format(tests[i][1], Math.ceil)).to.equal(tests[i][3]);
}
});
});
});

多语言

需求:数字很长时,由于排版的考虑,需要将数字显示的更短,转为​​指数​​​勉强可以,但对很多人还是不友好,如果能转为 ​​123.5百万​​ 这种形式就完美了。

numeral 提供了​​缩写​​​,比如可以将 ​​1230974​​​ 转为 ​​1.2m​​​(m,指​​百万​​):

// node_modules\numeral\tests\numeral.js
...
// abbreviations
[2000000000,'0.0a','2.0b'],
[1230974,'0.0a','1.2m'],
[1460,'0a','1k'],
[-104000,'0 a','-104 k'],
[999950,'0.0a','1.0m'],
[999999999,'0a','1b'],

请看示例:

const numeral = require('numeral');
var number5 = numeral(123456789).format('0.0a')
// 123.5m
console.log('number5: ', number5);

​123.5m​​​ 是多少,能否转为中文?笔者在 ​​chs.js​​ 中找到如下代码:

// node_modules\numeral\locales\chs.js

numeral.register('locale', 'chs', {
delimiters: {
thousands: ',',
decimal: '.'
},
abbreviations: {
thousand: '千',
million: '百万',
billion: '十亿',
trillion: '兆'
},
ordinal: function (number) {
return '.';
},
currency: {
symbol: '¥'
}
});

通过引入 ​​chs​​​ 并切换成中文,成功将 ​​123456789​​​ 转为 ​​123.5百万​​。请看示例:

const numeral = require('numeral');
// 加载中文
+ require('numeral/locales/chs')
// 切换成中文
+ numeral.locale('chs')
const number5 = numeral(123456789).format('0.0a')
// number5: 123.5百万
console.log('number5: ', number5);

Tip:对于单页面项目,在其他组件中若需要使用英文,比如不要 ​​123.5百万​​​,而要 ​​123.5m​​​,直接切换语言(​​numeral.locale('en')​​)即可。就像这样:

...
const number5 = numeral(123456789).format('0.0a')
// number5: 123.5百万
console.log('number5: ', number5);

+ numeral.locale('en')
const number6 = numeral(123456789).format('0.0a')

// number6: 123.5m
console.log('number6: ', number6);

笔者的示例

import React from 'react';
const numeral = require('numeral');
require('numeral/locales/chs')
numeral.locale('chs')

function Test() {
const number = numeral(1000).format('0,0');
// number: 1,000
console.log('number: ', number);
const number2 = numeral(123456789).format('0,0');
// number2: 123,456,789
console.log('number2: ', number2);
// 四舍五入
const number3 = numeral(1.93).format('0,0');
// number3: 2
console.log('number3: ', number3);
// 四舍五入
const number4 = numeral(1.23).format('0,0');
// number4: 1
console.log('number4: ', number4);

const number5 = numeral(123456789).format('0.0a')
// number5: 123.5百万
console.log('number5: ', number5);

numeral.locale('en')
const number6 = numeral(123456789).format('0.0a')

// number6: 123.5m
console.log('number6: ', number6);
return (
<div>
react 项目
</div>
)
}

export default Test

作者:彭加李​