reduce-precision 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/lib/format/index.b.js +667 -0
- package/lib/format/index.js +2 -5
- package/lib/format/kindex.b.js +667 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# reduce-precision
|
|
2
2
|
|
|
3
|
+
[](https://snyk.io/test/github/ArzDigitalLabs/reduce-precision?targetFile=package.json)
|
|
4
|
+
[](https://travis-ci.org/ArzDigitalLabs/reduce-precision)
|
|
5
|
+
[](https://codecov.io/github/ArzDigitalLabs/reduce-precision?branch=master)
|
|
6
|
+
[](https://codeclimate.com/github/ArzDigitalLabs/reduce-precision)
|
|
7
|
+
[](https://npmjs.org/package/reduce-precision)
|
|
8
|
+
|
|
3
9
|
`reduce-precision` is a versatile JavaScript/TypeScript package for formatting and reducing the precision of numbers, currencies, and percentages. It supports various templates, precision levels, languages, and output formats, making it easy to generate formatted strings for different use cases.
|
|
4
10
|
|
|
5
11
|
## Features
|
|
@@ -21,6 +27,8 @@ You can install `reduce-precision` using npm:
|
|
|
21
27
|
npm install reduce-precision
|
|
22
28
|
```
|
|
23
29
|
|
|
30
|
+
[](https://www.npmjs.com/package/reduce-precision)
|
|
31
|
+
|
|
24
32
|
## Usage
|
|
25
33
|
|
|
26
34
|
### JavaScript (CommonJS)
|
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
type;
|
|
4
|
+
this.options.Precision = 'auto' | 'high' | 'medium' | 'low';
|
|
5
|
+
class NumberFormatter {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = {
|
|
8
|
+
precision: 'high',
|
|
9
|
+
template: 'number',
|
|
10
|
+
language: 'en',
|
|
11
|
+
outputFormat: 'plain',
|
|
12
|
+
prefixMarker: 'i',
|
|
13
|
+
postfixMarker: 'i',
|
|
14
|
+
prefix: '',
|
|
15
|
+
postfix: '',
|
|
16
|
+
};
|
|
17
|
+
if (options) {
|
|
18
|
+
this.options = Object.assign(Object.assign({}, this.options), options);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
format(input) {
|
|
22
|
+
if (!input)
|
|
23
|
+
return 0;
|
|
24
|
+
let { precision, template } = this.options;
|
|
25
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = this.options;
|
|
26
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g))) {
|
|
27
|
+
template = 'number';
|
|
28
|
+
}
|
|
29
|
+
if (NumberFormatter.isENotation(input.toString())) {
|
|
30
|
+
input = NumberFormatter.convertENotationToRegularNumber(Number(input));
|
|
31
|
+
}
|
|
32
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
33
|
+
let numberString = input
|
|
34
|
+
.toString()
|
|
35
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
36
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
37
|
+
})
|
|
38
|
+
.replace(/[^\d.-]/g, '');
|
|
39
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
40
|
+
numberString = numberString
|
|
41
|
+
.replace(/^0+(?=\d)/g, '')
|
|
42
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
43
|
+
const number = Math.abs(Number(numberString));
|
|
44
|
+
let p, d, r, c;
|
|
45
|
+
let f = 0;
|
|
46
|
+
// Auto precision selection
|
|
47
|
+
if (precision === 'auto') {
|
|
48
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
49
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
50
|
+
precision = 'high';
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
precision = 'medium';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (template === 'number') {
|
|
57
|
+
precision = 'medium';
|
|
58
|
+
}
|
|
59
|
+
else if (template === 'percent') {
|
|
60
|
+
precision = 'low';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (precision === 'medium') {
|
|
64
|
+
if (number >= 0 && number < 0.0001) {
|
|
65
|
+
p = 33;
|
|
66
|
+
d = 4;
|
|
67
|
+
r = false;
|
|
68
|
+
c = true;
|
|
69
|
+
}
|
|
70
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
71
|
+
p = 7;
|
|
72
|
+
d = 4;
|
|
73
|
+
r = false;
|
|
74
|
+
c = false;
|
|
75
|
+
}
|
|
76
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
77
|
+
p = 5;
|
|
78
|
+
d = 3;
|
|
79
|
+
r = false;
|
|
80
|
+
c = false;
|
|
81
|
+
}
|
|
82
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
83
|
+
p = 3;
|
|
84
|
+
d = 2;
|
|
85
|
+
r = false;
|
|
86
|
+
c = false;
|
|
87
|
+
}
|
|
88
|
+
else if (number >= 0.1 && number < 1) {
|
|
89
|
+
p = 1;
|
|
90
|
+
d = 1;
|
|
91
|
+
r = false;
|
|
92
|
+
c = false;
|
|
93
|
+
}
|
|
94
|
+
else if (number >= 1 && number < 10) {
|
|
95
|
+
p = 3;
|
|
96
|
+
d = 3;
|
|
97
|
+
r = false;
|
|
98
|
+
c = false;
|
|
99
|
+
}
|
|
100
|
+
else if (number >= 10 && number < 100) {
|
|
101
|
+
p = 2;
|
|
102
|
+
d = 2;
|
|
103
|
+
r = false;
|
|
104
|
+
c = false;
|
|
105
|
+
}
|
|
106
|
+
else if (number >= 100 && number < 1000) {
|
|
107
|
+
p = 1;
|
|
108
|
+
d = 1;
|
|
109
|
+
r = false;
|
|
110
|
+
c = false;
|
|
111
|
+
}
|
|
112
|
+
else if (number >= 1000) {
|
|
113
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
114
|
+
p = 2 - x;
|
|
115
|
+
d = 2 - x;
|
|
116
|
+
r = true;
|
|
117
|
+
c = true;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
p = 0;
|
|
121
|
+
d = 0;
|
|
122
|
+
r = true;
|
|
123
|
+
c = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (precision === 'low') {
|
|
127
|
+
if (number >= 0 && number < 0.01) {
|
|
128
|
+
p = 2;
|
|
129
|
+
d = 0;
|
|
130
|
+
r = true;
|
|
131
|
+
c = false;
|
|
132
|
+
f = 2;
|
|
133
|
+
}
|
|
134
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
135
|
+
p = 2;
|
|
136
|
+
d = 1;
|
|
137
|
+
r = true;
|
|
138
|
+
c = false;
|
|
139
|
+
}
|
|
140
|
+
else if (number >= 0.1 && number < 1) {
|
|
141
|
+
p = 2;
|
|
142
|
+
d = 2;
|
|
143
|
+
r = true;
|
|
144
|
+
c = false;
|
|
145
|
+
}
|
|
146
|
+
else if (number >= 1 && number < 10) {
|
|
147
|
+
p = 2;
|
|
148
|
+
d = 2;
|
|
149
|
+
r = true;
|
|
150
|
+
c = false;
|
|
151
|
+
f = 2;
|
|
152
|
+
}
|
|
153
|
+
else if (number >= 10 && number < 100) {
|
|
154
|
+
p = 1;
|
|
155
|
+
d = 1;
|
|
156
|
+
r = true;
|
|
157
|
+
c = false;
|
|
158
|
+
f = 1;
|
|
159
|
+
}
|
|
160
|
+
else if (number >= 100 && number < 1000) {
|
|
161
|
+
p = 0;
|
|
162
|
+
d = 0;
|
|
163
|
+
r = true;
|
|
164
|
+
c = false;
|
|
165
|
+
}
|
|
166
|
+
else if (number >= 1000) {
|
|
167
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
168
|
+
p = 1 - x;
|
|
169
|
+
d = 1 - x;
|
|
170
|
+
r = true;
|
|
171
|
+
c = true;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
p = 0;
|
|
175
|
+
d = 0;
|
|
176
|
+
r = true;
|
|
177
|
+
c = true;
|
|
178
|
+
f = 2;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// precision === "high"
|
|
183
|
+
if (number >= 0 && number < 1) {
|
|
184
|
+
p = 33;
|
|
185
|
+
d = 4;
|
|
186
|
+
r = false;
|
|
187
|
+
c = false;
|
|
188
|
+
}
|
|
189
|
+
else if (number >= 1 && number < 10) {
|
|
190
|
+
p = 3;
|
|
191
|
+
d = 3;
|
|
192
|
+
r = true;
|
|
193
|
+
c = false;
|
|
194
|
+
}
|
|
195
|
+
else if (number >= 10 && number < 100) {
|
|
196
|
+
p = 2;
|
|
197
|
+
d = 2;
|
|
198
|
+
r = true;
|
|
199
|
+
c = false;
|
|
200
|
+
}
|
|
201
|
+
else if (number >= 100 && number < 1000) {
|
|
202
|
+
p = 2;
|
|
203
|
+
d = 2;
|
|
204
|
+
r = true;
|
|
205
|
+
c = false;
|
|
206
|
+
}
|
|
207
|
+
else if (number >= 1000 && number < 10000) {
|
|
208
|
+
p = 1;
|
|
209
|
+
d = 1;
|
|
210
|
+
r = true;
|
|
211
|
+
c = false;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
p = 0;
|
|
215
|
+
d = 0;
|
|
216
|
+
r = true;
|
|
217
|
+
c = false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return NumberFormatter.reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
221
|
+
}
|
|
222
|
+
setPrecision(precision) {
|
|
223
|
+
this.options.this.options.precision = precision;
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
setTemplate(template) {
|
|
227
|
+
this.options.template = template;
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
setLanguage(language) {
|
|
231
|
+
this.options.language = language;
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
setOutputFormat(outputFormat) {
|
|
235
|
+
this.options.outputFormat = outputFormat;
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
setPrefixMarker(prefixMarker) {
|
|
239
|
+
this.options.prefixMarker = prefixMarker;
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
setPostfixMarker(postfixMarker) {
|
|
243
|
+
this.options.postfixMarker = postfixMarker;
|
|
244
|
+
return this;
|
|
245
|
+
}
|
|
246
|
+
setPrefix(prefix) {
|
|
247
|
+
this.options.prefix = prefix;
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
setPostfix(postfix) {
|
|
251
|
+
this.options.postfix = postfix;
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
static isENotation(input) {
|
|
255
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/.test(input);
|
|
256
|
+
}
|
|
257
|
+
static convertENotationToRegularNumber(eNotation) {
|
|
258
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
259
|
+
const coefficientLength = coefficientStr
|
|
260
|
+
.replace('.', '')
|
|
261
|
+
.replace('-', '').length;
|
|
262
|
+
const exponent = parseFloat(exponentStr);
|
|
263
|
+
const ;
|
|
264
|
+
this.options.precision = Math.max(coefficientLength - exponent, 1);
|
|
265
|
+
return eNotation.toFixed(precision);
|
|
266
|
+
}
|
|
267
|
+
static reducePrecision(numberString, options, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
268
|
+
// ... (implementation remains the same)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function isENotation(input) {
|
|
272
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/.test(input);
|
|
273
|
+
}
|
|
274
|
+
function convertENotationToRegularNumber(eNotation) {
|
|
275
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
276
|
+
const coefficientLength = coefficientStr
|
|
277
|
+
.replace('.', '')
|
|
278
|
+
.replace('-', '').length;
|
|
279
|
+
const exponent = parseFloat(exponentStr);
|
|
280
|
+
const ;
|
|
281
|
+
this.options.precision = Math.max(coefficientLength - exponent, 1);
|
|
282
|
+
return eNotation.toFixed(precision);
|
|
283
|
+
}
|
|
284
|
+
function format(input, options = {
|
|
285
|
+
precision: 'high',
|
|
286
|
+
template: 'number',
|
|
287
|
+
language: 'en',
|
|
288
|
+
outputFormat: 'plain',
|
|
289
|
+
prefixMarker: 'i',
|
|
290
|
+
postfixMarker: 'i',
|
|
291
|
+
prefix: '',
|
|
292
|
+
postfix: '',
|
|
293
|
+
}) {
|
|
294
|
+
let { precision, template } = options;
|
|
295
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = options;
|
|
296
|
+
if (!input)
|
|
297
|
+
return 0;
|
|
298
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
299
|
+
template = 'number';
|
|
300
|
+
if (isENotation(input.toString())) {
|
|
301
|
+
input = convertENotationToRegularNumber(Number(input));
|
|
302
|
+
}
|
|
303
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
304
|
+
let numberString = input
|
|
305
|
+
.toString()
|
|
306
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
307
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
308
|
+
})
|
|
309
|
+
.replace(/[^\d.-]/g, '');
|
|
310
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
311
|
+
numberString = numberString
|
|
312
|
+
.replace(/^0+(?=\d)/g, '')
|
|
313
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
314
|
+
const number = Math.abs(Number(numberString));
|
|
315
|
+
let p, d, r, c;
|
|
316
|
+
let f = 0;
|
|
317
|
+
// Auto precision selection
|
|
318
|
+
if (precision === 'auto') {
|
|
319
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
320
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
321
|
+
this.options.precision = 'high';
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
this.options.precision = 'medium';
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else if (template === 'number') {
|
|
328
|
+
this.options.precision = 'medium';
|
|
329
|
+
}
|
|
330
|
+
else if (template === 'percent') {
|
|
331
|
+
this.options.precision = 'low';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (precision === 'medium') {
|
|
335
|
+
if (number >= 0 && number < 0.0001) {
|
|
336
|
+
p = 33;
|
|
337
|
+
d = 4;
|
|
338
|
+
r = false;
|
|
339
|
+
c = true;
|
|
340
|
+
}
|
|
341
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
342
|
+
p = 7;
|
|
343
|
+
d = 4;
|
|
344
|
+
r = false;
|
|
345
|
+
c = false;
|
|
346
|
+
}
|
|
347
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
348
|
+
p = 5;
|
|
349
|
+
d = 3;
|
|
350
|
+
r = false;
|
|
351
|
+
c = false;
|
|
352
|
+
}
|
|
353
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
354
|
+
p = 3;
|
|
355
|
+
d = 2;
|
|
356
|
+
r = false;
|
|
357
|
+
c = false;
|
|
358
|
+
}
|
|
359
|
+
else if (number >= 0.1 && number < 1) {
|
|
360
|
+
p = 1;
|
|
361
|
+
d = 1;
|
|
362
|
+
r = false;
|
|
363
|
+
c = false;
|
|
364
|
+
}
|
|
365
|
+
else if (number >= 1 && number < 10) {
|
|
366
|
+
p = 3;
|
|
367
|
+
d = 3;
|
|
368
|
+
r = false;
|
|
369
|
+
c = false;
|
|
370
|
+
}
|
|
371
|
+
else if (number >= 10 && number < 100) {
|
|
372
|
+
p = 2;
|
|
373
|
+
d = 2;
|
|
374
|
+
r = false;
|
|
375
|
+
c = false;
|
|
376
|
+
}
|
|
377
|
+
else if (number >= 100 && number < 1000) {
|
|
378
|
+
p = 1;
|
|
379
|
+
d = 1;
|
|
380
|
+
r = false;
|
|
381
|
+
c = false;
|
|
382
|
+
}
|
|
383
|
+
else if (number >= 1000) {
|
|
384
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
385
|
+
p = 2 - x;
|
|
386
|
+
d = 2 - x;
|
|
387
|
+
r = true;
|
|
388
|
+
c = true;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
p = 0;
|
|
392
|
+
d = 0;
|
|
393
|
+
r = true;
|
|
394
|
+
c = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else if (precision === 'low') {
|
|
398
|
+
if (number >= 0 && number < 0.01) {
|
|
399
|
+
p = 2;
|
|
400
|
+
d = 0;
|
|
401
|
+
r = true;
|
|
402
|
+
c = false;
|
|
403
|
+
f = 2;
|
|
404
|
+
}
|
|
405
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
406
|
+
p = 2;
|
|
407
|
+
d = 1;
|
|
408
|
+
r = true;
|
|
409
|
+
c = false;
|
|
410
|
+
}
|
|
411
|
+
else if (number >= 0.1 && number < 1) {
|
|
412
|
+
p = 2;
|
|
413
|
+
d = 2;
|
|
414
|
+
r = true;
|
|
415
|
+
c = false;
|
|
416
|
+
}
|
|
417
|
+
else if (number >= 1 && number < 10) {
|
|
418
|
+
p = 2;
|
|
419
|
+
d = 2;
|
|
420
|
+
r = true;
|
|
421
|
+
c = false;
|
|
422
|
+
f = 2;
|
|
423
|
+
}
|
|
424
|
+
else if (number >= 10 && number < 100) {
|
|
425
|
+
p = 1;
|
|
426
|
+
d = 1;
|
|
427
|
+
r = true;
|
|
428
|
+
c = false;
|
|
429
|
+
f = 1;
|
|
430
|
+
}
|
|
431
|
+
else if (number >= 100 && number < 1000) {
|
|
432
|
+
p = 0;
|
|
433
|
+
d = 0;
|
|
434
|
+
r = true;
|
|
435
|
+
c = false;
|
|
436
|
+
}
|
|
437
|
+
else if (number >= 1000) {
|
|
438
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
439
|
+
p = 1 - x;
|
|
440
|
+
d = 1 - x;
|
|
441
|
+
r = true;
|
|
442
|
+
c = true;
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
p = 0;
|
|
446
|
+
d = 0;
|
|
447
|
+
r = true;
|
|
448
|
+
c = true;
|
|
449
|
+
f = 2;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
// precision === "high"
|
|
454
|
+
if (number >= 0 && number < 1) {
|
|
455
|
+
p = 33;
|
|
456
|
+
d = 4;
|
|
457
|
+
r = false;
|
|
458
|
+
c = false;
|
|
459
|
+
}
|
|
460
|
+
else if (number >= 1 && number < 10) {
|
|
461
|
+
p = 3;
|
|
462
|
+
d = 3;
|
|
463
|
+
r = true;
|
|
464
|
+
c = false;
|
|
465
|
+
}
|
|
466
|
+
else if (number >= 10 && number < 100) {
|
|
467
|
+
p = 2;
|
|
468
|
+
d = 2;
|
|
469
|
+
r = true;
|
|
470
|
+
c = false;
|
|
471
|
+
}
|
|
472
|
+
else if (number >= 100 && number < 1000) {
|
|
473
|
+
p = 2;
|
|
474
|
+
d = 2;
|
|
475
|
+
r = true;
|
|
476
|
+
c = false;
|
|
477
|
+
}
|
|
478
|
+
else if (number >= 1000 && number < 10000) {
|
|
479
|
+
p = 1;
|
|
480
|
+
d = 1;
|
|
481
|
+
r = true;
|
|
482
|
+
c = false;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
p = 0;
|
|
486
|
+
d = 0;
|
|
487
|
+
r = true;
|
|
488
|
+
c = false;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
492
|
+
}
|
|
493
|
+
function reducePrecision(numberString, options, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
494
|
+
if (!numberString)
|
|
495
|
+
return 0;
|
|
496
|
+
numberString = numberString.toString();
|
|
497
|
+
const maxthis, options, Precision = 30;
|
|
498
|
+
const maxIntegerDigits = 21;
|
|
499
|
+
const scaleUnits = template.match(/^(number|percent)$/g)
|
|
500
|
+
? {
|
|
501
|
+
'': '',
|
|
502
|
+
K: ' هزار',
|
|
503
|
+
M: ' میلیون',
|
|
504
|
+
B: ' میلیارد',
|
|
505
|
+
T: ' تریلیون',
|
|
506
|
+
Qd: ' کادریلیون',
|
|
507
|
+
Qt: ' کنتیلیون',
|
|
508
|
+
}
|
|
509
|
+
: {
|
|
510
|
+
'': '',
|
|
511
|
+
K: ' هزار ت',
|
|
512
|
+
M: ' میلیون ت',
|
|
513
|
+
B: ' میلیارد ت',
|
|
514
|
+
T: ' همت',
|
|
515
|
+
Qd: ' هزار همت',
|
|
516
|
+
Qt: ' میلیون همت',
|
|
517
|
+
};
|
|
518
|
+
let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
|
|
519
|
+
if (!parts) {
|
|
520
|
+
return 0;
|
|
521
|
+
}
|
|
522
|
+
const sign = parts[1] || '';
|
|
523
|
+
let wholeNumberStr = parts[2];
|
|
524
|
+
let fractionalZeroStr = parts[3];
|
|
525
|
+
let fractionalNonZeroStr = parts[4];
|
|
526
|
+
let unitPrefix = '';
|
|
527
|
+
let unitPostfix = '';
|
|
528
|
+
if (fractionalZeroStr.length >= maxPrecision) {
|
|
529
|
+
// Number is smaller than maximum precision
|
|
530
|
+
fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
|
|
531
|
+
fractionalNonZeroStr = '1';
|
|
532
|
+
}
|
|
533
|
+
else if (fractionalZeroStr.length + nonZeroDigits > precision) {
|
|
534
|
+
// decrease non-zero digits
|
|
535
|
+
nonZeroDigits = precision - fractionalZeroStr.length;
|
|
536
|
+
if (nonZeroDigits < 1)
|
|
537
|
+
nonZeroDigits = 1;
|
|
538
|
+
}
|
|
539
|
+
else if (wholeNumberStr.length > maxIntegerDigits) {
|
|
540
|
+
wholeNumberStr = '0';
|
|
541
|
+
fractionalZeroStr = '';
|
|
542
|
+
fractionalNonZeroStr = '';
|
|
543
|
+
}
|
|
544
|
+
// compress large numbers
|
|
545
|
+
if (compress && wholeNumberStr.length >= 4) {
|
|
546
|
+
const scaleUnitKeys = Object.keys(scaleUnits);
|
|
547
|
+
let scaledWholeNumber = wholeNumberStr;
|
|
548
|
+
let unitIndex = 0;
|
|
549
|
+
while (+scaledWholeNumber > 999 && unitIndex < scaleUnitKeys.length - 1) {
|
|
550
|
+
scaledWholeNumber = (+scaledWholeNumber / 1000).toFixed(2);
|
|
551
|
+
unitIndex++;
|
|
552
|
+
}
|
|
553
|
+
unitPostfix = scaleUnitKeys[unitIndex];
|
|
554
|
+
parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(scaledWholeNumber.toString());
|
|
555
|
+
if (!parts) {
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
// sign = parts[1] || "";
|
|
559
|
+
wholeNumberStr = parts[2];
|
|
560
|
+
fractionalZeroStr = parts[3];
|
|
561
|
+
fractionalNonZeroStr = parts[4];
|
|
562
|
+
}
|
|
563
|
+
// Truncate the fractional part or round it
|
|
564
|
+
// if (precision > 0 && nonZeroDigits > 0 && fractionalNonZeroStr.length > nonZeroDigits) {
|
|
565
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
566
|
+
if (!round) {
|
|
567
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
if (parseInt(fractionalNonZeroStr[nonZeroDigits]) < 5) {
|
|
571
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
fractionalNonZeroStr = (parseInt(fractionalNonZeroStr.substring(0, nonZeroDigits)) + 1).toString();
|
|
575
|
+
// If overflow occurs (e.g., 999 + 1 = 1000), adjust the substring length
|
|
576
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
577
|
+
if (fractionalZeroStr.length > 0) {
|
|
578
|
+
fractionalZeroStr = fractionalZeroStr.substring(0, fractionalZeroStr.length - 1);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
wholeNumberStr = (Number(wholeNumberStr) + 1).toString();
|
|
582
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(1);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Using dex style
|
|
589
|
+
if (compress && fractionalZeroStr !== '' && unitPostfix === '') {
|
|
590
|
+
fractionalZeroStr =
|
|
591
|
+
'0' +
|
|
592
|
+
fractionalZeroStr.length.toString().replace(/\d/g, function (match) {
|
|
593
|
+
return [
|
|
594
|
+
'₀',
|
|
595
|
+
'₁',
|
|
596
|
+
'₂',
|
|
597
|
+
'₃',
|
|
598
|
+
'₄',
|
|
599
|
+
'₅',
|
|
600
|
+
'₆',
|
|
601
|
+
'₇',
|
|
602
|
+
'₈',
|
|
603
|
+
'₉',
|
|
604
|
+
][parseInt(match, 10)];
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
let fractionalPartStr = `${fractionalZeroStr}${fractionalNonZeroStr}`;
|
|
608
|
+
fractionalPartStr = fractionalPartStr.substring(0, precision);
|
|
609
|
+
fractionalPartStr = fractionalPartStr.replace(/^(\d*[1-9])0+$/g, '$1');
|
|
610
|
+
// Output Formating, Prefix, Postfix
|
|
611
|
+
if (template === 'usd') {
|
|
612
|
+
unitPrefix = language === 'en' ? '$' : '';
|
|
613
|
+
}
|
|
614
|
+
else if (template === 'irr') {
|
|
615
|
+
if (!unitPostfix)
|
|
616
|
+
unitPostfix = language === 'fa' ? ' ر' : ' R';
|
|
617
|
+
}
|
|
618
|
+
else if (template === 'irt') {
|
|
619
|
+
if (!unitPostfix)
|
|
620
|
+
unitPostfix = language === 'fa' ? ' ت' : ' T';
|
|
621
|
+
}
|
|
622
|
+
else if (template === 'percent') {
|
|
623
|
+
if (language === 'en') {
|
|
624
|
+
unitPostfix += '%';
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
unitPostfix += !unitPostfix ? '٪' : ' درصد';
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
unitPrefix = prefix + unitPrefix;
|
|
631
|
+
unitPostfix += postfix;
|
|
632
|
+
if (outputFormat === 'html') {
|
|
633
|
+
if (unitPrefix)
|
|
634
|
+
unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
|
|
635
|
+
if (unitPostfix)
|
|
636
|
+
unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
|
|
637
|
+
}
|
|
638
|
+
else if (outputFormat === 'markdown') {
|
|
639
|
+
if (unitPrefix)
|
|
640
|
+
unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
|
|
641
|
+
if (unitPostfix)
|
|
642
|
+
unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
|
|
643
|
+
}
|
|
644
|
+
const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
|
|
645
|
+
const fixedDecimalZeroStr = fixedDecimalZeros
|
|
646
|
+
? '.'.padEnd(fixedDecimalZeros + 1, '0')
|
|
647
|
+
: '';
|
|
648
|
+
let out = '';
|
|
649
|
+
if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
|
|
650
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}${unitPostfix}`;
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}${unitPostfix}`;
|
|
654
|
+
}
|
|
655
|
+
// Convert output to Persian numerals if language is "fa"
|
|
656
|
+
if (language === 'fa') {
|
|
657
|
+
out = out
|
|
658
|
+
.replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
|
|
659
|
+
.replace(/,/g, '٬')
|
|
660
|
+
.replace(/\./g, '٫')
|
|
661
|
+
.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
662
|
+
return String(scaleUnits[c]);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return out;
|
|
666
|
+
}
|
|
667
|
+
exports.default = format;
|
package/lib/format/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
function isENotation(input) {
|
|
4
|
-
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)
|
|
4
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)$/.test(input);
|
|
5
5
|
}
|
|
6
6
|
function convertENotationToRegularNumber(eNotation) {
|
|
7
7
|
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
@@ -395,8 +395,5 @@ function reducePrecision(numberString, precision = 30, nonZeroDigits = 4, round
|
|
|
395
395
|
}
|
|
396
396
|
return out;
|
|
397
397
|
}
|
|
398
|
-
console.log(format(
|
|
399
|
-
console.log(format(3.1227533815325955e-30, { precision: 'low' }));
|
|
400
|
-
console.log(format(3123123123, { precision: 'low' }));
|
|
401
|
-
console.log(format(2, { precision: 'low' }));
|
|
398
|
+
console.log(format('0.000024160785036984196', { precision: 'medium', template: 'usd' }));
|
|
402
399
|
exports.default = format;
|
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
type;
|
|
4
|
+
this.options.Precision = 'auto' | 'high' | 'medium' | 'low';
|
|
5
|
+
class NumberFormatter {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.options = {
|
|
8
|
+
precision: 'high',
|
|
9
|
+
template: 'number',
|
|
10
|
+
language: 'en',
|
|
11
|
+
outputFormat: 'plain',
|
|
12
|
+
prefixMarker: 'i',
|
|
13
|
+
postfixMarker: 'i',
|
|
14
|
+
prefix: '',
|
|
15
|
+
postfix: '',
|
|
16
|
+
};
|
|
17
|
+
if (options) {
|
|
18
|
+
this.options = Object.assign(Object.assign({}, this.options), options);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
format(input) {
|
|
22
|
+
if (!input)
|
|
23
|
+
return 0;
|
|
24
|
+
let { precision, template } = this.options;
|
|
25
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = this.options;
|
|
26
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g))) {
|
|
27
|
+
template = 'number';
|
|
28
|
+
}
|
|
29
|
+
if (NumberFormatter.isENotation(input.toString())) {
|
|
30
|
+
input = NumberFormatter.convertENotationToRegularNumber(Number(input));
|
|
31
|
+
}
|
|
32
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
33
|
+
let numberString = input
|
|
34
|
+
.toString()
|
|
35
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
36
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
37
|
+
})
|
|
38
|
+
.replace(/[^\d.-]/g, '');
|
|
39
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
40
|
+
numberString = numberString
|
|
41
|
+
.replace(/^0+(?=\d)/g, '')
|
|
42
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
43
|
+
const number = Math.abs(Number(numberString));
|
|
44
|
+
let p, d, r, c;
|
|
45
|
+
let f = 0;
|
|
46
|
+
// Auto precision selection
|
|
47
|
+
if (precision === 'auto') {
|
|
48
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
49
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
50
|
+
precision = 'high';
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
precision = 'medium';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else if (template === 'number') {
|
|
57
|
+
precision = 'medium';
|
|
58
|
+
}
|
|
59
|
+
else if (template === 'percent') {
|
|
60
|
+
precision = 'low';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (precision === 'medium') {
|
|
64
|
+
if (number >= 0 && number < 0.0001) {
|
|
65
|
+
p = 33;
|
|
66
|
+
d = 4;
|
|
67
|
+
r = false;
|
|
68
|
+
c = true;
|
|
69
|
+
}
|
|
70
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
71
|
+
p = 7;
|
|
72
|
+
d = 4;
|
|
73
|
+
r = false;
|
|
74
|
+
c = false;
|
|
75
|
+
}
|
|
76
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
77
|
+
p = 5;
|
|
78
|
+
d = 3;
|
|
79
|
+
r = false;
|
|
80
|
+
c = false;
|
|
81
|
+
}
|
|
82
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
83
|
+
p = 3;
|
|
84
|
+
d = 2;
|
|
85
|
+
r = false;
|
|
86
|
+
c = false;
|
|
87
|
+
}
|
|
88
|
+
else if (number >= 0.1 && number < 1) {
|
|
89
|
+
p = 1;
|
|
90
|
+
d = 1;
|
|
91
|
+
r = false;
|
|
92
|
+
c = false;
|
|
93
|
+
}
|
|
94
|
+
else if (number >= 1 && number < 10) {
|
|
95
|
+
p = 3;
|
|
96
|
+
d = 3;
|
|
97
|
+
r = false;
|
|
98
|
+
c = false;
|
|
99
|
+
}
|
|
100
|
+
else if (number >= 10 && number < 100) {
|
|
101
|
+
p = 2;
|
|
102
|
+
d = 2;
|
|
103
|
+
r = false;
|
|
104
|
+
c = false;
|
|
105
|
+
}
|
|
106
|
+
else if (number >= 100 && number < 1000) {
|
|
107
|
+
p = 1;
|
|
108
|
+
d = 1;
|
|
109
|
+
r = false;
|
|
110
|
+
c = false;
|
|
111
|
+
}
|
|
112
|
+
else if (number >= 1000) {
|
|
113
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
114
|
+
p = 2 - x;
|
|
115
|
+
d = 2 - x;
|
|
116
|
+
r = true;
|
|
117
|
+
c = true;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
p = 0;
|
|
121
|
+
d = 0;
|
|
122
|
+
r = true;
|
|
123
|
+
c = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (precision === 'low') {
|
|
127
|
+
if (number >= 0 && number < 0.01) {
|
|
128
|
+
p = 2;
|
|
129
|
+
d = 0;
|
|
130
|
+
r = true;
|
|
131
|
+
c = false;
|
|
132
|
+
f = 2;
|
|
133
|
+
}
|
|
134
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
135
|
+
p = 2;
|
|
136
|
+
d = 1;
|
|
137
|
+
r = true;
|
|
138
|
+
c = false;
|
|
139
|
+
}
|
|
140
|
+
else if (number >= 0.1 && number < 1) {
|
|
141
|
+
p = 2;
|
|
142
|
+
d = 2;
|
|
143
|
+
r = true;
|
|
144
|
+
c = false;
|
|
145
|
+
}
|
|
146
|
+
else if (number >= 1 && number < 10) {
|
|
147
|
+
p = 2;
|
|
148
|
+
d = 2;
|
|
149
|
+
r = true;
|
|
150
|
+
c = false;
|
|
151
|
+
f = 2;
|
|
152
|
+
}
|
|
153
|
+
else if (number >= 10 && number < 100) {
|
|
154
|
+
p = 1;
|
|
155
|
+
d = 1;
|
|
156
|
+
r = true;
|
|
157
|
+
c = false;
|
|
158
|
+
f = 1;
|
|
159
|
+
}
|
|
160
|
+
else if (number >= 100 && number < 1000) {
|
|
161
|
+
p = 0;
|
|
162
|
+
d = 0;
|
|
163
|
+
r = true;
|
|
164
|
+
c = false;
|
|
165
|
+
}
|
|
166
|
+
else if (number >= 1000) {
|
|
167
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
168
|
+
p = 1 - x;
|
|
169
|
+
d = 1 - x;
|
|
170
|
+
r = true;
|
|
171
|
+
c = true;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
p = 0;
|
|
175
|
+
d = 0;
|
|
176
|
+
r = true;
|
|
177
|
+
c = true;
|
|
178
|
+
f = 2;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// precision === "high"
|
|
183
|
+
if (number >= 0 && number < 1) {
|
|
184
|
+
p = 33;
|
|
185
|
+
d = 4;
|
|
186
|
+
r = false;
|
|
187
|
+
c = false;
|
|
188
|
+
}
|
|
189
|
+
else if (number >= 1 && number < 10) {
|
|
190
|
+
p = 3;
|
|
191
|
+
d = 3;
|
|
192
|
+
r = true;
|
|
193
|
+
c = false;
|
|
194
|
+
}
|
|
195
|
+
else if (number >= 10 && number < 100) {
|
|
196
|
+
p = 2;
|
|
197
|
+
d = 2;
|
|
198
|
+
r = true;
|
|
199
|
+
c = false;
|
|
200
|
+
}
|
|
201
|
+
else if (number >= 100 && number < 1000) {
|
|
202
|
+
p = 2;
|
|
203
|
+
d = 2;
|
|
204
|
+
r = true;
|
|
205
|
+
c = false;
|
|
206
|
+
}
|
|
207
|
+
else if (number >= 1000 && number < 10000) {
|
|
208
|
+
p = 1;
|
|
209
|
+
d = 1;
|
|
210
|
+
r = true;
|
|
211
|
+
c = false;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
p = 0;
|
|
215
|
+
d = 0;
|
|
216
|
+
r = true;
|
|
217
|
+
c = false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return NumberFormatter.reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
221
|
+
}
|
|
222
|
+
setPrecision(precision) {
|
|
223
|
+
this.options.this.options.precision = precision;
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
setTemplate(template) {
|
|
227
|
+
this.options.template = template;
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
setLanguage(language) {
|
|
231
|
+
this.options.language = language;
|
|
232
|
+
return this;
|
|
233
|
+
}
|
|
234
|
+
setOutputFormat(outputFormat) {
|
|
235
|
+
this.options.outputFormat = outputFormat;
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
setPrefixMarker(prefixMarker) {
|
|
239
|
+
this.options.prefixMarker = prefixMarker;
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
setPostfixMarker(postfixMarker) {
|
|
243
|
+
this.options.postfixMarker = postfixMarker;
|
|
244
|
+
return this;
|
|
245
|
+
}
|
|
246
|
+
setPrefix(prefix) {
|
|
247
|
+
this.options.prefix = prefix;
|
|
248
|
+
return this;
|
|
249
|
+
}
|
|
250
|
+
setPostfix(postfix) {
|
|
251
|
+
this.options.postfix = postfix;
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
static isENotation(input) {
|
|
255
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/.test(input);
|
|
256
|
+
}
|
|
257
|
+
static convertENotationToRegularNumber(eNotation) {
|
|
258
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
259
|
+
const coefficientLength = coefficientStr
|
|
260
|
+
.replace('.', '')
|
|
261
|
+
.replace('-', '').length;
|
|
262
|
+
const exponent = parseFloat(exponentStr);
|
|
263
|
+
const ;
|
|
264
|
+
this.options.precision = Math.max(coefficientLength - exponent, 1);
|
|
265
|
+
return eNotation.toFixed(precision);
|
|
266
|
+
}
|
|
267
|
+
static reducePrecision(numberString, options, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
268
|
+
// ... (implementation remains the same)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function isENotation(input) {
|
|
272
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/.test(input);
|
|
273
|
+
}
|
|
274
|
+
function convertENotationToRegularNumber(eNotation) {
|
|
275
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
276
|
+
const coefficientLength = coefficientStr
|
|
277
|
+
.replace('.', '')
|
|
278
|
+
.replace('-', '').length;
|
|
279
|
+
const exponent = parseFloat(exponentStr);
|
|
280
|
+
const ;
|
|
281
|
+
this.options.precision = Math.max(coefficientLength - exponent, 1);
|
|
282
|
+
return eNotation.toFixed(precision);
|
|
283
|
+
}
|
|
284
|
+
function format(input, options = {
|
|
285
|
+
precision: 'high',
|
|
286
|
+
template: 'number',
|
|
287
|
+
language: 'en',
|
|
288
|
+
outputFormat: 'plain',
|
|
289
|
+
prefixMarker: 'i',
|
|
290
|
+
postfixMarker: 'i',
|
|
291
|
+
prefix: '',
|
|
292
|
+
postfix: '',
|
|
293
|
+
}) {
|
|
294
|
+
let { precision, template } = options;
|
|
295
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = options;
|
|
296
|
+
if (!input)
|
|
297
|
+
return 0;
|
|
298
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
299
|
+
template = 'number';
|
|
300
|
+
if (isENotation(input.toString())) {
|
|
301
|
+
input = convertENotationToRegularNumber(Number(input));
|
|
302
|
+
}
|
|
303
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
304
|
+
let numberString = input
|
|
305
|
+
.toString()
|
|
306
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
307
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
308
|
+
})
|
|
309
|
+
.replace(/[^\d.-]/g, '');
|
|
310
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
311
|
+
numberString = numberString
|
|
312
|
+
.replace(/^0+(?=\d)/g, '')
|
|
313
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
314
|
+
const number = Math.abs(Number(numberString));
|
|
315
|
+
let p, d, r, c;
|
|
316
|
+
let f = 0;
|
|
317
|
+
// Auto precision selection
|
|
318
|
+
if (precision === 'auto') {
|
|
319
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
320
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
321
|
+
this.options.precision = 'high';
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
this.options.precision = 'medium';
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else if (template === 'number') {
|
|
328
|
+
this.options.precision = 'medium';
|
|
329
|
+
}
|
|
330
|
+
else if (template === 'percent') {
|
|
331
|
+
this.options.precision = 'low';
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (precision === 'medium') {
|
|
335
|
+
if (number >= 0 && number < 0.0001) {
|
|
336
|
+
p = 33;
|
|
337
|
+
d = 4;
|
|
338
|
+
r = false;
|
|
339
|
+
c = true;
|
|
340
|
+
}
|
|
341
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
342
|
+
p = 7;
|
|
343
|
+
d = 4;
|
|
344
|
+
r = false;
|
|
345
|
+
c = false;
|
|
346
|
+
}
|
|
347
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
348
|
+
p = 5;
|
|
349
|
+
d = 3;
|
|
350
|
+
r = false;
|
|
351
|
+
c = false;
|
|
352
|
+
}
|
|
353
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
354
|
+
p = 3;
|
|
355
|
+
d = 2;
|
|
356
|
+
r = false;
|
|
357
|
+
c = false;
|
|
358
|
+
}
|
|
359
|
+
else if (number >= 0.1 && number < 1) {
|
|
360
|
+
p = 1;
|
|
361
|
+
d = 1;
|
|
362
|
+
r = false;
|
|
363
|
+
c = false;
|
|
364
|
+
}
|
|
365
|
+
else if (number >= 1 && number < 10) {
|
|
366
|
+
p = 3;
|
|
367
|
+
d = 3;
|
|
368
|
+
r = false;
|
|
369
|
+
c = false;
|
|
370
|
+
}
|
|
371
|
+
else if (number >= 10 && number < 100) {
|
|
372
|
+
p = 2;
|
|
373
|
+
d = 2;
|
|
374
|
+
r = false;
|
|
375
|
+
c = false;
|
|
376
|
+
}
|
|
377
|
+
else if (number >= 100 && number < 1000) {
|
|
378
|
+
p = 1;
|
|
379
|
+
d = 1;
|
|
380
|
+
r = false;
|
|
381
|
+
c = false;
|
|
382
|
+
}
|
|
383
|
+
else if (number >= 1000) {
|
|
384
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
385
|
+
p = 2 - x;
|
|
386
|
+
d = 2 - x;
|
|
387
|
+
r = true;
|
|
388
|
+
c = true;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
p = 0;
|
|
392
|
+
d = 0;
|
|
393
|
+
r = true;
|
|
394
|
+
c = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
else if (precision === 'low') {
|
|
398
|
+
if (number >= 0 && number < 0.01) {
|
|
399
|
+
p = 2;
|
|
400
|
+
d = 0;
|
|
401
|
+
r = true;
|
|
402
|
+
c = false;
|
|
403
|
+
f = 2;
|
|
404
|
+
}
|
|
405
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
406
|
+
p = 2;
|
|
407
|
+
d = 1;
|
|
408
|
+
r = true;
|
|
409
|
+
c = false;
|
|
410
|
+
}
|
|
411
|
+
else if (number >= 0.1 && number < 1) {
|
|
412
|
+
p = 2;
|
|
413
|
+
d = 2;
|
|
414
|
+
r = true;
|
|
415
|
+
c = false;
|
|
416
|
+
}
|
|
417
|
+
else if (number >= 1 && number < 10) {
|
|
418
|
+
p = 2;
|
|
419
|
+
d = 2;
|
|
420
|
+
r = true;
|
|
421
|
+
c = false;
|
|
422
|
+
f = 2;
|
|
423
|
+
}
|
|
424
|
+
else if (number >= 10 && number < 100) {
|
|
425
|
+
p = 1;
|
|
426
|
+
d = 1;
|
|
427
|
+
r = true;
|
|
428
|
+
c = false;
|
|
429
|
+
f = 1;
|
|
430
|
+
}
|
|
431
|
+
else if (number >= 100 && number < 1000) {
|
|
432
|
+
p = 0;
|
|
433
|
+
d = 0;
|
|
434
|
+
r = true;
|
|
435
|
+
c = false;
|
|
436
|
+
}
|
|
437
|
+
else if (number >= 1000) {
|
|
438
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
439
|
+
p = 1 - x;
|
|
440
|
+
d = 1 - x;
|
|
441
|
+
r = true;
|
|
442
|
+
c = true;
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
p = 0;
|
|
446
|
+
d = 0;
|
|
447
|
+
r = true;
|
|
448
|
+
c = true;
|
|
449
|
+
f = 2;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
// precision === "high"
|
|
454
|
+
if (number >= 0 && number < 1) {
|
|
455
|
+
p = 33;
|
|
456
|
+
d = 4;
|
|
457
|
+
r = false;
|
|
458
|
+
c = false;
|
|
459
|
+
}
|
|
460
|
+
else if (number >= 1 && number < 10) {
|
|
461
|
+
p = 3;
|
|
462
|
+
d = 3;
|
|
463
|
+
r = true;
|
|
464
|
+
c = false;
|
|
465
|
+
}
|
|
466
|
+
else if (number >= 10 && number < 100) {
|
|
467
|
+
p = 2;
|
|
468
|
+
d = 2;
|
|
469
|
+
r = true;
|
|
470
|
+
c = false;
|
|
471
|
+
}
|
|
472
|
+
else if (number >= 100 && number < 1000) {
|
|
473
|
+
p = 2;
|
|
474
|
+
d = 2;
|
|
475
|
+
r = true;
|
|
476
|
+
c = false;
|
|
477
|
+
}
|
|
478
|
+
else if (number >= 1000 && number < 10000) {
|
|
479
|
+
p = 1;
|
|
480
|
+
d = 1;
|
|
481
|
+
r = true;
|
|
482
|
+
c = false;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
p = 0;
|
|
486
|
+
d = 0;
|
|
487
|
+
r = true;
|
|
488
|
+
c = false;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
492
|
+
}
|
|
493
|
+
function reducePrecision(numberString, options, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
494
|
+
if (!numberString)
|
|
495
|
+
return 0;
|
|
496
|
+
numberString = numberString.toString();
|
|
497
|
+
const maxthis, options, Precision = 30;
|
|
498
|
+
const maxIntegerDigits = 21;
|
|
499
|
+
const scaleUnits = template.match(/^(number|percent)$/g)
|
|
500
|
+
? {
|
|
501
|
+
'': '',
|
|
502
|
+
K: ' هزار',
|
|
503
|
+
M: ' میلیون',
|
|
504
|
+
B: ' میلیارد',
|
|
505
|
+
T: ' تریلیون',
|
|
506
|
+
Qd: ' کادریلیون',
|
|
507
|
+
Qt: ' کنتیلیون',
|
|
508
|
+
}
|
|
509
|
+
: {
|
|
510
|
+
'': '',
|
|
511
|
+
K: ' هزار ت',
|
|
512
|
+
M: ' میلیون ت',
|
|
513
|
+
B: ' میلیارد ت',
|
|
514
|
+
T: ' همت',
|
|
515
|
+
Qd: ' هزار همت',
|
|
516
|
+
Qt: ' میلیون همت',
|
|
517
|
+
};
|
|
518
|
+
let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
|
|
519
|
+
if (!parts) {
|
|
520
|
+
return 0;
|
|
521
|
+
}
|
|
522
|
+
const sign = parts[1] || '';
|
|
523
|
+
let wholeNumberStr = parts[2];
|
|
524
|
+
let fractionalZeroStr = parts[3];
|
|
525
|
+
let fractionalNonZeroStr = parts[4];
|
|
526
|
+
let unitPrefix = '';
|
|
527
|
+
let unitPostfix = '';
|
|
528
|
+
if (fractionalZeroStr.length >= maxPrecision) {
|
|
529
|
+
// Number is smaller than maximum precision
|
|
530
|
+
fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
|
|
531
|
+
fractionalNonZeroStr = '1';
|
|
532
|
+
}
|
|
533
|
+
else if (fractionalZeroStr.length + nonZeroDigits > precision) {
|
|
534
|
+
// decrease non-zero digits
|
|
535
|
+
nonZeroDigits = precision - fractionalZeroStr.length;
|
|
536
|
+
if (nonZeroDigits < 1)
|
|
537
|
+
nonZeroDigits = 1;
|
|
538
|
+
}
|
|
539
|
+
else if (wholeNumberStr.length > maxIntegerDigits) {
|
|
540
|
+
wholeNumberStr = '0';
|
|
541
|
+
fractionalZeroStr = '';
|
|
542
|
+
fractionalNonZeroStr = '';
|
|
543
|
+
}
|
|
544
|
+
// compress large numbers
|
|
545
|
+
if (compress && wholeNumberStr.length >= 4) {
|
|
546
|
+
const scaleUnitKeys = Object.keys(scaleUnits);
|
|
547
|
+
let scaledWholeNumber = wholeNumberStr;
|
|
548
|
+
let unitIndex = 0;
|
|
549
|
+
while (+scaledWholeNumber > 999 && unitIndex < scaleUnitKeys.length - 1) {
|
|
550
|
+
scaledWholeNumber = (+scaledWholeNumber / 1000).toFixed(2);
|
|
551
|
+
unitIndex++;
|
|
552
|
+
}
|
|
553
|
+
unitPostfix = scaleUnitKeys[unitIndex];
|
|
554
|
+
parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(scaledWholeNumber.toString());
|
|
555
|
+
if (!parts) {
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
// sign = parts[1] || "";
|
|
559
|
+
wholeNumberStr = parts[2];
|
|
560
|
+
fractionalZeroStr = parts[3];
|
|
561
|
+
fractionalNonZeroStr = parts[4];
|
|
562
|
+
}
|
|
563
|
+
// Truncate the fractional part or round it
|
|
564
|
+
// if (precision > 0 && nonZeroDigits > 0 && fractionalNonZeroStr.length > nonZeroDigits) {
|
|
565
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
566
|
+
if (!round) {
|
|
567
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
if (parseInt(fractionalNonZeroStr[nonZeroDigits]) < 5) {
|
|
571
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
fractionalNonZeroStr = (parseInt(fractionalNonZeroStr.substring(0, nonZeroDigits)) + 1).toString();
|
|
575
|
+
// If overflow occurs (e.g., 999 + 1 = 1000), adjust the substring length
|
|
576
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
577
|
+
if (fractionalZeroStr.length > 0) {
|
|
578
|
+
fractionalZeroStr = fractionalZeroStr.substring(0, fractionalZeroStr.length - 1);
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
wholeNumberStr = (Number(wholeNumberStr) + 1).toString();
|
|
582
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(1);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
// Using dex style
|
|
589
|
+
if (compress && fractionalZeroStr !== '' && unitPostfix === '') {
|
|
590
|
+
fractionalZeroStr =
|
|
591
|
+
'0' +
|
|
592
|
+
fractionalZeroStr.length.toString().replace(/\d/g, function (match) {
|
|
593
|
+
return [
|
|
594
|
+
'₀',
|
|
595
|
+
'₁',
|
|
596
|
+
'₂',
|
|
597
|
+
'₃',
|
|
598
|
+
'₄',
|
|
599
|
+
'₅',
|
|
600
|
+
'₆',
|
|
601
|
+
'₇',
|
|
602
|
+
'₈',
|
|
603
|
+
'₉',
|
|
604
|
+
][parseInt(match, 10)];
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
let fractionalPartStr = `${fractionalZeroStr}${fractionalNonZeroStr}`;
|
|
608
|
+
fractionalPartStr = fractionalPartStr.substring(0, precision);
|
|
609
|
+
fractionalPartStr = fractionalPartStr.replace(/^(\d*[1-9])0+$/g, '$1');
|
|
610
|
+
// Output Formating, Prefix, Postfix
|
|
611
|
+
if (template === 'usd') {
|
|
612
|
+
unitPrefix = language === 'en' ? '$' : '';
|
|
613
|
+
}
|
|
614
|
+
else if (template === 'irr') {
|
|
615
|
+
if (!unitPostfix)
|
|
616
|
+
unitPostfix = language === 'fa' ? ' ر' : ' R';
|
|
617
|
+
}
|
|
618
|
+
else if (template === 'irt') {
|
|
619
|
+
if (!unitPostfix)
|
|
620
|
+
unitPostfix = language === 'fa' ? ' ت' : ' T';
|
|
621
|
+
}
|
|
622
|
+
else if (template === 'percent') {
|
|
623
|
+
if (language === 'en') {
|
|
624
|
+
unitPostfix += '%';
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
unitPostfix += !unitPostfix ? '٪' : ' درصد';
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
unitPrefix = prefix + unitPrefix;
|
|
631
|
+
unitPostfix += postfix;
|
|
632
|
+
if (outputFormat === 'html') {
|
|
633
|
+
if (unitPrefix)
|
|
634
|
+
unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
|
|
635
|
+
if (unitPostfix)
|
|
636
|
+
unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
|
|
637
|
+
}
|
|
638
|
+
else if (outputFormat === 'markdown') {
|
|
639
|
+
if (unitPrefix)
|
|
640
|
+
unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
|
|
641
|
+
if (unitPostfix)
|
|
642
|
+
unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
|
|
643
|
+
}
|
|
644
|
+
const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
|
|
645
|
+
const fixedDecimalZeroStr = fixedDecimalZeros
|
|
646
|
+
? '.'.padEnd(fixedDecimalZeros + 1, '0')
|
|
647
|
+
: '';
|
|
648
|
+
let out = '';
|
|
649
|
+
if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
|
|
650
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}${unitPostfix}`;
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}${unitPostfix}`;
|
|
654
|
+
}
|
|
655
|
+
// Convert output to Persian numerals if language is "fa"
|
|
656
|
+
if (language === 'fa') {
|
|
657
|
+
out = out
|
|
658
|
+
.replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
|
|
659
|
+
.replace(/,/g, '٬')
|
|
660
|
+
.replace(/\./g, '٫')
|
|
661
|
+
.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
662
|
+
return String(scaleUnits[c]);
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return out;
|
|
666
|
+
}
|
|
667
|
+
exports.default = format;
|