reduce-precision 0.0.3 → 1.0.1
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 +112 -14
- package/lib/format/index.d.ts +33 -2
- package/lib/format/index.js +432 -373
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -2
- package/package.json +1 -1
- package/lib/format/index.b.js +0 -667
- package/lib/format/kindex.b.js +0 -667
package/lib/format/index.js
CHANGED
|
@@ -1,399 +1,458 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
precision: 'high',
|
|
17
|
-
template: 'number',
|
|
18
|
-
language: 'en',
|
|
19
|
-
outputFormat: 'plain',
|
|
20
|
-
prefixMarker: 'i',
|
|
21
|
-
postfixMarker: 'i',
|
|
22
|
-
prefix: '',
|
|
23
|
-
postfix: '',
|
|
24
|
-
}) {
|
|
25
|
-
let { precision, template } = options;
|
|
26
|
-
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = options;
|
|
27
|
-
if (!input)
|
|
28
|
-
return 0;
|
|
29
|
-
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
30
|
-
template = 'number';
|
|
31
|
-
if (isENotation(input.toString())) {
|
|
32
|
-
input = convertENotationToRegularNumber(Number(input));
|
|
3
|
+
class NumberFormatter {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.options = {
|
|
6
|
+
language: 'en',
|
|
7
|
+
template: 'number',
|
|
8
|
+
precision: 'high',
|
|
9
|
+
outputFormat: 'plain',
|
|
10
|
+
prefixMarker: 'i',
|
|
11
|
+
postfixMarker: 'i',
|
|
12
|
+
prefix: '',
|
|
13
|
+
postfix: '',
|
|
14
|
+
};
|
|
15
|
+
this.options = Object.assign(Object.assign({}, this.options), options);
|
|
33
16
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
.replace(/^0+(?=\d)/g, '')
|
|
44
|
-
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
45
|
-
const number = Math.abs(Number(numberString));
|
|
46
|
-
let p, d, r, c;
|
|
47
|
-
let f = 0;
|
|
48
|
-
// Auto precision selection
|
|
49
|
-
if (precision === 'auto') {
|
|
50
|
-
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
51
|
-
if (number >= 0.0001 && number < 100000000000) {
|
|
52
|
-
precision = 'high';
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
precision = 'medium';
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
else if (template === 'number') {
|
|
59
|
-
precision = 'medium';
|
|
60
|
-
}
|
|
61
|
-
else if (template === 'percent') {
|
|
62
|
-
precision = 'low';
|
|
63
|
-
}
|
|
17
|
+
setLanguage(lang, config = {}) {
|
|
18
|
+
this.options.language = lang;
|
|
19
|
+
this.options.prefixMarker =
|
|
20
|
+
config.prefixMarker || this.options.prefixMarker;
|
|
21
|
+
this.options.postfixMarker =
|
|
22
|
+
config.postfixMarker || this.options.postfixMarker;
|
|
23
|
+
this.options.prefix = config.prefix || this.options.prefix;
|
|
24
|
+
this.options.postfix = config.postfix || this.options.postfix;
|
|
25
|
+
return this;
|
|
64
26
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
r = false;
|
|
70
|
-
c = true;
|
|
71
|
-
}
|
|
72
|
-
else if (number >= 0.0001 && number < 0.001) {
|
|
73
|
-
p = 7;
|
|
74
|
-
d = 4;
|
|
75
|
-
r = false;
|
|
76
|
-
c = false;
|
|
77
|
-
}
|
|
78
|
-
else if (number >= 0.001 && number < 0.01) {
|
|
79
|
-
p = 5;
|
|
80
|
-
d = 3;
|
|
81
|
-
r = false;
|
|
82
|
-
c = false;
|
|
83
|
-
}
|
|
84
|
-
else if (number >= 0.001 && number < 0.1) {
|
|
85
|
-
p = 3;
|
|
86
|
-
d = 2;
|
|
87
|
-
r = false;
|
|
88
|
-
c = false;
|
|
89
|
-
}
|
|
90
|
-
else if (number >= 0.1 && number < 1) {
|
|
91
|
-
p = 1;
|
|
92
|
-
d = 1;
|
|
93
|
-
r = false;
|
|
94
|
-
c = false;
|
|
95
|
-
}
|
|
96
|
-
else if (number >= 1 && number < 10) {
|
|
97
|
-
p = 3;
|
|
98
|
-
d = 3;
|
|
99
|
-
r = false;
|
|
100
|
-
c = false;
|
|
101
|
-
}
|
|
102
|
-
else if (number >= 10 && number < 100) {
|
|
103
|
-
p = 2;
|
|
104
|
-
d = 2;
|
|
105
|
-
r = false;
|
|
106
|
-
c = false;
|
|
107
|
-
}
|
|
108
|
-
else if (number >= 100 && number < 1000) {
|
|
109
|
-
p = 1;
|
|
110
|
-
d = 1;
|
|
111
|
-
r = false;
|
|
112
|
-
c = false;
|
|
113
|
-
}
|
|
114
|
-
else if (number >= 1000) {
|
|
115
|
-
const x = Math.floor(Math.log10(number)) % 3;
|
|
116
|
-
p = 2 - x;
|
|
117
|
-
d = 2 - x;
|
|
118
|
-
r = true;
|
|
119
|
-
c = true;
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
p = 0;
|
|
123
|
-
d = 0;
|
|
124
|
-
r = true;
|
|
125
|
-
c = true;
|
|
126
|
-
}
|
|
27
|
+
setTemplate(template, precision) {
|
|
28
|
+
this.options.template = template;
|
|
29
|
+
this.options.precision = precision;
|
|
30
|
+
return this;
|
|
127
31
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
r = true;
|
|
133
|
-
c = false;
|
|
134
|
-
f = 2;
|
|
135
|
-
}
|
|
136
|
-
else if (number >= 0.01 && number < 0.1) {
|
|
137
|
-
p = 2;
|
|
138
|
-
d = 1;
|
|
139
|
-
r = true;
|
|
140
|
-
c = false;
|
|
141
|
-
}
|
|
142
|
-
else if (number >= 0.1 && number < 1) {
|
|
143
|
-
p = 2;
|
|
144
|
-
d = 2;
|
|
145
|
-
r = true;
|
|
146
|
-
c = false;
|
|
147
|
-
}
|
|
148
|
-
else if (number >= 1 && number < 10) {
|
|
149
|
-
p = 2;
|
|
150
|
-
d = 2;
|
|
151
|
-
r = true;
|
|
152
|
-
c = false;
|
|
153
|
-
f = 2;
|
|
154
|
-
}
|
|
155
|
-
else if (number >= 10 && number < 100) {
|
|
156
|
-
p = 1;
|
|
157
|
-
d = 1;
|
|
158
|
-
r = true;
|
|
159
|
-
c = false;
|
|
160
|
-
f = 1;
|
|
161
|
-
}
|
|
162
|
-
else if (number >= 100 && number < 1000) {
|
|
163
|
-
p = 0;
|
|
164
|
-
d = 0;
|
|
165
|
-
r = true;
|
|
166
|
-
c = false;
|
|
167
|
-
}
|
|
168
|
-
else if (number >= 1000) {
|
|
169
|
-
const x = Math.floor(Math.log10(number)) % 3;
|
|
170
|
-
p = 1 - x;
|
|
171
|
-
d = 1 - x;
|
|
172
|
-
r = true;
|
|
173
|
-
c = true;
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
p = 0;
|
|
177
|
-
d = 0;
|
|
178
|
-
r = true;
|
|
179
|
-
c = true;
|
|
180
|
-
f = 2;
|
|
181
|
-
}
|
|
32
|
+
toJson(input) {
|
|
33
|
+
const formattedObject = this.format(input);
|
|
34
|
+
delete formattedObject.value;
|
|
35
|
+
return formattedObject;
|
|
182
36
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
p = 33;
|
|
187
|
-
d = 4;
|
|
188
|
-
r = false;
|
|
189
|
-
c = false;
|
|
190
|
-
}
|
|
191
|
-
else if (number >= 1 && number < 10) {
|
|
192
|
-
p = 3;
|
|
193
|
-
d = 3;
|
|
194
|
-
r = true;
|
|
195
|
-
c = false;
|
|
196
|
-
}
|
|
197
|
-
else if (number >= 10 && number < 100) {
|
|
198
|
-
p = 2;
|
|
199
|
-
d = 2;
|
|
200
|
-
r = true;
|
|
201
|
-
c = false;
|
|
202
|
-
}
|
|
203
|
-
else if (number >= 100 && number < 1000) {
|
|
204
|
-
p = 2;
|
|
205
|
-
d = 2;
|
|
206
|
-
r = true;
|
|
207
|
-
c = false;
|
|
208
|
-
}
|
|
209
|
-
else if (number >= 1000 && number < 10000) {
|
|
210
|
-
p = 1;
|
|
211
|
-
d = 1;
|
|
212
|
-
r = true;
|
|
213
|
-
c = false;
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
p = 0;
|
|
217
|
-
d = 0;
|
|
218
|
-
r = true;
|
|
219
|
-
c = false;
|
|
220
|
-
}
|
|
37
|
+
toString(input) {
|
|
38
|
+
const formattedObject = this.format(input);
|
|
39
|
+
return formattedObject.value || '';
|
|
221
40
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return 0;
|
|
227
|
-
numberString = numberString.toString();
|
|
228
|
-
const maxPrecision = 30;
|
|
229
|
-
const maxIntegerDigits = 21;
|
|
230
|
-
const scaleUnits = template.match(/^(number|percent)$/g)
|
|
231
|
-
? {
|
|
232
|
-
'': '',
|
|
233
|
-
K: ' هزار',
|
|
234
|
-
M: ' میلیون',
|
|
235
|
-
B: ' میلیارد',
|
|
236
|
-
T: ' تریلیون',
|
|
237
|
-
Qd: ' کادریلیون',
|
|
238
|
-
Qt: ' کنتیلیون',
|
|
239
|
-
}
|
|
240
|
-
: {
|
|
241
|
-
'': '',
|
|
242
|
-
K: ' هزار ت',
|
|
243
|
-
M: ' میلیون ت',
|
|
244
|
-
B: ' میلیارد ت',
|
|
245
|
-
T: ' همت',
|
|
246
|
-
Qd: ' هزار همت',
|
|
247
|
-
Qt: ' میلیون همت',
|
|
248
|
-
};
|
|
249
|
-
let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
|
|
250
|
-
if (!parts) {
|
|
251
|
-
return 0;
|
|
41
|
+
toPlainString(input) {
|
|
42
|
+
this.options.outputFormat = 'plain';
|
|
43
|
+
const formattedObject = this.format(input);
|
|
44
|
+
return formattedObject.value || '';
|
|
252
45
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
let unitPrefix = '';
|
|
258
|
-
let unitPostfix = '';
|
|
259
|
-
if (fractionalZeroStr.length >= maxPrecision) {
|
|
260
|
-
// Number is smaller than maximum precision
|
|
261
|
-
fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
|
|
262
|
-
fractionalNonZeroStr = '1';
|
|
46
|
+
toHtmlString(input) {
|
|
47
|
+
this.options.outputFormat = 'html';
|
|
48
|
+
const formattedObject = this.format(input);
|
|
49
|
+
return formattedObject.value || '';
|
|
263
50
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
nonZeroDigits = 1;
|
|
51
|
+
toMdString(input) {
|
|
52
|
+
this.options.outputFormat = 'markdown';
|
|
53
|
+
const formattedObject = this.format(input);
|
|
54
|
+
return formattedObject.value || '';
|
|
269
55
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
fractionalNonZeroStr = '';
|
|
56
|
+
// Private methods...
|
|
57
|
+
isENotation(input) {
|
|
58
|
+
return /^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)$/.test(input);
|
|
274
59
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
60
|
+
format(input) {
|
|
61
|
+
let { precision, template } = this.options;
|
|
62
|
+
const { language, outputFormat, prefixMarker, postfixMarker, prefix, postfix, } = this.options;
|
|
63
|
+
if (!input)
|
|
64
|
+
return {};
|
|
65
|
+
if (!(template === null || template === void 0 ? void 0 : template.match(/^(number|usd|irt|irr|percent)$/g)))
|
|
66
|
+
template = 'number';
|
|
67
|
+
if (this.isENotation(input.toString())) {
|
|
68
|
+
input = this.convertENotationToRegularNumber(Number(input));
|
|
69
|
+
}
|
|
70
|
+
// Replace each Persian/Arabic numeral in the string with its English counterpart and strip all non-numeric chars
|
|
71
|
+
let numberString = input
|
|
72
|
+
.toString()
|
|
73
|
+
.replace(/[\u0660-\u0669\u06F0-\u06F9]/g, function (match) {
|
|
74
|
+
return String(match.charCodeAt(0) & 0xf);
|
|
75
|
+
})
|
|
76
|
+
.replace(/[^\d.-]/g, '');
|
|
77
|
+
// Stripping leading zeros and trailing zeros after a decimal point
|
|
78
|
+
numberString = numberString
|
|
79
|
+
.replace(/^0+(?=\d)/g, '')
|
|
80
|
+
.replace(/(?<=\.\d*)0+$|(?<=\.\d)0+\b/g, '');
|
|
81
|
+
const number = Math.abs(Number(numberString));
|
|
82
|
+
let p, d, r, c;
|
|
83
|
+
let f = 0;
|
|
84
|
+
// Auto precision selection
|
|
85
|
+
if (precision === 'auto') {
|
|
86
|
+
if (template.match(/^(usd|irt|irr)$/g)) {
|
|
87
|
+
if (number >= 0.0001 && number < 100000000000) {
|
|
88
|
+
precision = 'high';
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
precision = 'medium';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (template === 'number') {
|
|
95
|
+
precision = 'medium';
|
|
96
|
+
}
|
|
97
|
+
else if (template === 'percent') {
|
|
98
|
+
precision = 'low';
|
|
99
|
+
}
|
|
283
100
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
101
|
+
if (precision === 'medium') {
|
|
102
|
+
if (number >= 0 && number < 0.0001) {
|
|
103
|
+
p = 33;
|
|
104
|
+
d = 4;
|
|
105
|
+
r = false;
|
|
106
|
+
c = true;
|
|
107
|
+
}
|
|
108
|
+
else if (number >= 0.0001 && number < 0.001) {
|
|
109
|
+
p = 7;
|
|
110
|
+
d = 4;
|
|
111
|
+
r = false;
|
|
112
|
+
c = false;
|
|
113
|
+
}
|
|
114
|
+
else if (number >= 0.001 && number < 0.01) {
|
|
115
|
+
p = 5;
|
|
116
|
+
d = 3;
|
|
117
|
+
r = false;
|
|
118
|
+
c = false;
|
|
119
|
+
}
|
|
120
|
+
else if (number >= 0.001 && number < 0.1) {
|
|
121
|
+
p = 3;
|
|
122
|
+
d = 2;
|
|
123
|
+
r = false;
|
|
124
|
+
c = false;
|
|
125
|
+
}
|
|
126
|
+
else if (number >= 0.1 && number < 1) {
|
|
127
|
+
p = 1;
|
|
128
|
+
d = 1;
|
|
129
|
+
r = false;
|
|
130
|
+
c = false;
|
|
131
|
+
}
|
|
132
|
+
else if (number >= 1 && number < 10) {
|
|
133
|
+
p = 3;
|
|
134
|
+
d = 3;
|
|
135
|
+
r = false;
|
|
136
|
+
c = false;
|
|
137
|
+
}
|
|
138
|
+
else if (number >= 10 && number < 100) {
|
|
139
|
+
p = 2;
|
|
140
|
+
d = 2;
|
|
141
|
+
r = false;
|
|
142
|
+
c = false;
|
|
143
|
+
}
|
|
144
|
+
else if (number >= 100 && number < 1000) {
|
|
145
|
+
p = 1;
|
|
146
|
+
d = 1;
|
|
147
|
+
r = false;
|
|
148
|
+
c = false;
|
|
149
|
+
}
|
|
150
|
+
else if (number >= 1000) {
|
|
151
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
152
|
+
p = 2 - x;
|
|
153
|
+
d = 2 - x;
|
|
154
|
+
r = true;
|
|
155
|
+
c = true;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
p = 0;
|
|
159
|
+
d = 0;
|
|
160
|
+
r = true;
|
|
161
|
+
c = true;
|
|
162
|
+
}
|
|
288
163
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
164
|
+
else if (precision === 'low') {
|
|
165
|
+
if (number >= 0 && number < 0.01) {
|
|
166
|
+
p = 2;
|
|
167
|
+
d = 0;
|
|
168
|
+
r = true;
|
|
169
|
+
c = false;
|
|
170
|
+
f = 2;
|
|
171
|
+
}
|
|
172
|
+
else if (number >= 0.01 && number < 0.1) {
|
|
173
|
+
p = 2;
|
|
174
|
+
d = 1;
|
|
175
|
+
r = true;
|
|
176
|
+
c = false;
|
|
177
|
+
}
|
|
178
|
+
else if (number >= 0.1 && number < 1) {
|
|
179
|
+
p = 2;
|
|
180
|
+
d = 2;
|
|
181
|
+
r = true;
|
|
182
|
+
c = false;
|
|
183
|
+
}
|
|
184
|
+
else if (number >= 1 && number < 10) {
|
|
185
|
+
p = 2;
|
|
186
|
+
d = 2;
|
|
187
|
+
r = true;
|
|
188
|
+
c = false;
|
|
189
|
+
f = 2;
|
|
190
|
+
}
|
|
191
|
+
else if (number >= 10 && number < 100) {
|
|
192
|
+
p = 1;
|
|
193
|
+
d = 1;
|
|
194
|
+
r = true;
|
|
195
|
+
c = false;
|
|
196
|
+
f = 1;
|
|
197
|
+
}
|
|
198
|
+
else if (number >= 100 && number < 1000) {
|
|
199
|
+
p = 0;
|
|
200
|
+
d = 0;
|
|
201
|
+
r = true;
|
|
202
|
+
c = false;
|
|
203
|
+
}
|
|
204
|
+
else if (number >= 1000) {
|
|
205
|
+
const x = Math.floor(Math.log10(number)) % 3;
|
|
206
|
+
p = 1 - x;
|
|
207
|
+
d = 1 - x;
|
|
208
|
+
r = true;
|
|
209
|
+
c = true;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
p = 0;
|
|
213
|
+
d = 0;
|
|
214
|
+
r = true;
|
|
215
|
+
c = true;
|
|
216
|
+
f = 2;
|
|
217
|
+
}
|
|
299
218
|
}
|
|
300
219
|
else {
|
|
301
|
-
|
|
220
|
+
// precision === "high"
|
|
221
|
+
if (number >= 0 && number < 1) {
|
|
222
|
+
p = 33;
|
|
223
|
+
d = 4;
|
|
224
|
+
r = false;
|
|
225
|
+
c = false;
|
|
226
|
+
}
|
|
227
|
+
else if (number >= 1 && number < 10) {
|
|
228
|
+
p = 3;
|
|
229
|
+
d = 3;
|
|
230
|
+
r = true;
|
|
231
|
+
c = false;
|
|
232
|
+
}
|
|
233
|
+
else if (number >= 10 && number < 100) {
|
|
234
|
+
p = 2;
|
|
235
|
+
d = 2;
|
|
236
|
+
r = true;
|
|
237
|
+
c = false;
|
|
238
|
+
}
|
|
239
|
+
else if (number >= 100 && number < 1000) {
|
|
240
|
+
p = 2;
|
|
241
|
+
d = 2;
|
|
242
|
+
r = true;
|
|
243
|
+
c = false;
|
|
244
|
+
}
|
|
245
|
+
else if (number >= 1000 && number < 10000) {
|
|
246
|
+
p = 1;
|
|
247
|
+
d = 1;
|
|
248
|
+
r = true;
|
|
249
|
+
c = false;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
p = 0;
|
|
253
|
+
d = 0;
|
|
254
|
+
r = true;
|
|
255
|
+
c = false;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return this.reducePrecision(numberString, p, d, r, c, f, template, language, outputFormat, prefixMarker, postfixMarker, prefix, postfix);
|
|
259
|
+
}
|
|
260
|
+
convertENotationToRegularNumber(eNotation) {
|
|
261
|
+
const [coefficientStr, exponentStr] = eNotation.toString().split('e');
|
|
262
|
+
const coefficientLength = coefficientStr
|
|
263
|
+
.replace('.', '')
|
|
264
|
+
.replace('-', '').length;
|
|
265
|
+
const exponent = parseFloat(exponentStr);
|
|
266
|
+
const precision = Math.max(coefficientLength - exponent, 1);
|
|
267
|
+
return eNotation.toFixed(precision);
|
|
268
|
+
}
|
|
269
|
+
reducePrecision(numberString, precision = 30, nonZeroDigits = 4, round = false, compress = false, fixedDecimalZeros = 0, template = 'number', language = 'en', outputFormat = 'plain', prefixMarker = 'span', postfixMarker = 'span', prefix = '', postfix = '') {
|
|
270
|
+
if (!numberString) {
|
|
271
|
+
return {};
|
|
272
|
+
}
|
|
273
|
+
numberString = numberString.toString();
|
|
274
|
+
const maxPrecision = 30;
|
|
275
|
+
const maxIntegerDigits = 21;
|
|
276
|
+
const scaleUnits = template.match(/^(number|percent)$/g)
|
|
277
|
+
? {
|
|
278
|
+
'': '',
|
|
279
|
+
K: ' هزار',
|
|
280
|
+
M: ' میلیون',
|
|
281
|
+
B: ' میلیارد',
|
|
282
|
+
T: ' تریلیون',
|
|
283
|
+
Qd: ' کادریلیون',
|
|
284
|
+
Qt: ' کنتیلیون',
|
|
285
|
+
}
|
|
286
|
+
: {
|
|
287
|
+
'': '',
|
|
288
|
+
K: ' هزار ت',
|
|
289
|
+
M: ' میلیون ت',
|
|
290
|
+
B: ' میلیارد ت',
|
|
291
|
+
T: ' همت',
|
|
292
|
+
Qd: ' هزار همت',
|
|
293
|
+
Qt: ' میلیون همت',
|
|
294
|
+
};
|
|
295
|
+
let parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(numberString);
|
|
296
|
+
if (!parts) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
const sign = parts[1] || '';
|
|
300
|
+
let wholeNumberStr = parts[2];
|
|
301
|
+
let fractionalZeroStr = parts[3];
|
|
302
|
+
let fractionalNonZeroStr = parts[4];
|
|
303
|
+
let unitPrefix = '';
|
|
304
|
+
let unitPostfix = '';
|
|
305
|
+
if (fractionalZeroStr.length >= maxPrecision) {
|
|
306
|
+
// Number is smaller than maximum precision
|
|
307
|
+
fractionalZeroStr = '0'.padEnd(maxPrecision - 1, '0');
|
|
308
|
+
fractionalNonZeroStr = '1';
|
|
309
|
+
}
|
|
310
|
+
else if (fractionalZeroStr.length + nonZeroDigits > precision) {
|
|
311
|
+
// decrease non-zero digits
|
|
312
|
+
nonZeroDigits = precision - fractionalZeroStr.length;
|
|
313
|
+
if (nonZeroDigits < 1)
|
|
314
|
+
nonZeroDigits = 1;
|
|
315
|
+
}
|
|
316
|
+
else if (wholeNumberStr.length > maxIntegerDigits) {
|
|
317
|
+
wholeNumberStr = '0';
|
|
318
|
+
fractionalZeroStr = '';
|
|
319
|
+
fractionalNonZeroStr = '';
|
|
320
|
+
}
|
|
321
|
+
// compress large numbers
|
|
322
|
+
if (compress && wholeNumberStr.length >= 4) {
|
|
323
|
+
const scaleUnitKeys = Object.keys(scaleUnits);
|
|
324
|
+
let scaledWholeNumber = wholeNumberStr;
|
|
325
|
+
let unitIndex = 0;
|
|
326
|
+
while (+scaledWholeNumber > 999 && unitIndex < scaleUnitKeys.length - 1) {
|
|
327
|
+
scaledWholeNumber = (+scaledWholeNumber / 1000).toFixed(2);
|
|
328
|
+
unitIndex++;
|
|
329
|
+
}
|
|
330
|
+
unitPostfix = scaleUnitKeys[unitIndex];
|
|
331
|
+
parts = /^(-)?(\d+)\.?([0]*)(\d*)$/g.exec(scaledWholeNumber.toString());
|
|
332
|
+
if (!parts) {
|
|
333
|
+
return {};
|
|
334
|
+
}
|
|
335
|
+
// sign = parts[1] || "";
|
|
336
|
+
wholeNumberStr = parts[2];
|
|
337
|
+
fractionalZeroStr = parts[3];
|
|
338
|
+
fractionalNonZeroStr = parts[4];
|
|
339
|
+
}
|
|
340
|
+
// Truncate the fractional part or round it
|
|
341
|
+
// if (precision > 0 && nonZeroDigits > 0 && fractionalNonZeroStr.length > nonZeroDigits) {
|
|
342
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
343
|
+
if (!round) {
|
|
302
344
|
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
303
345
|
}
|
|
304
346
|
else {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
347
|
+
if (parseInt(fractionalNonZeroStr[nonZeroDigits]) < 5) {
|
|
348
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(0, nonZeroDigits);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
fractionalNonZeroStr = (parseInt(fractionalNonZeroStr.substring(0, nonZeroDigits)) + 1).toString();
|
|
352
|
+
// If overflow occurs (e.g., 999 + 1 = 1000), adjust the substring length
|
|
353
|
+
if (fractionalNonZeroStr.length > nonZeroDigits) {
|
|
354
|
+
if (fractionalZeroStr.length > 0) {
|
|
355
|
+
fractionalZeroStr = fractionalZeroStr.substring(0, fractionalZeroStr.length - 1);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
wholeNumberStr = (Number(wholeNumberStr) + 1).toString();
|
|
359
|
+
fractionalNonZeroStr = fractionalNonZeroStr.substring(1);
|
|
360
|
+
}
|
|
314
361
|
}
|
|
315
362
|
}
|
|
316
363
|
}
|
|
317
364
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
else if (template === 'percent') {
|
|
354
|
-
if (language === 'en') {
|
|
355
|
-
unitPostfix += '%';
|
|
365
|
+
const orginalFractionalZeroStr = fractionalZeroStr;
|
|
366
|
+
// Using dex style
|
|
367
|
+
if (compress && fractionalZeroStr !== '' && unitPostfix === '') {
|
|
368
|
+
fractionalZeroStr =
|
|
369
|
+
'0' +
|
|
370
|
+
fractionalZeroStr.length.toString().replace(/\d/g, function (match) {
|
|
371
|
+
return [
|
|
372
|
+
'₀',
|
|
373
|
+
'₁',
|
|
374
|
+
'₂',
|
|
375
|
+
'₃',
|
|
376
|
+
'₄',
|
|
377
|
+
'₅',
|
|
378
|
+
'₆',
|
|
379
|
+
'₇',
|
|
380
|
+
'₈',
|
|
381
|
+
'₉',
|
|
382
|
+
][parseInt(match, 10)];
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
let fractionalPartStr = `${fractionalZeroStr}${fractionalNonZeroStr}`;
|
|
386
|
+
fractionalPartStr = fractionalPartStr.substring(0, precision);
|
|
387
|
+
fractionalPartStr = fractionalPartStr.replace(/^(\d*[1-9])0+$/g, '$1');
|
|
388
|
+
// Output Formating, Prefix, Postfix
|
|
389
|
+
if (template === 'usd') {
|
|
390
|
+
unitPrefix = language === 'en' ? '$' : '';
|
|
391
|
+
}
|
|
392
|
+
else if (template === 'irr') {
|
|
393
|
+
if (!unitPostfix)
|
|
394
|
+
unitPostfix = language === 'fa' ? ' ر' : ' R';
|
|
395
|
+
}
|
|
396
|
+
else if (template === 'irt') {
|
|
397
|
+
if (!unitPostfix)
|
|
398
|
+
unitPostfix = language === 'fa' ? ' ت' : ' T';
|
|
356
399
|
}
|
|
357
|
-
else {
|
|
358
|
-
|
|
400
|
+
else if (template === 'percent') {
|
|
401
|
+
if (language === 'en') {
|
|
402
|
+
unitPostfix += '%';
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
unitPostfix += !unitPostfix ? '٪' : ' درصد';
|
|
406
|
+
}
|
|
359
407
|
}
|
|
408
|
+
unitPrefix = prefix + unitPrefix;
|
|
409
|
+
unitPostfix += postfix;
|
|
410
|
+
if (outputFormat === 'html') {
|
|
411
|
+
if (unitPrefix)
|
|
412
|
+
unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
|
|
413
|
+
if (unitPostfix)
|
|
414
|
+
unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
|
|
415
|
+
}
|
|
416
|
+
else if (outputFormat === 'markdown') {
|
|
417
|
+
if (unitPrefix)
|
|
418
|
+
unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
|
|
419
|
+
if (unitPostfix)
|
|
420
|
+
unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
|
|
421
|
+
}
|
|
422
|
+
const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
|
|
423
|
+
const fixedDecimalZeroStr = fixedDecimalZeros
|
|
424
|
+
? '.'.padEnd(fixedDecimalZeros + 1, '0')
|
|
425
|
+
: '';
|
|
426
|
+
let out = '';
|
|
427
|
+
if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
|
|
428
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}${unitPostfix}`;
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}${unitPostfix}`;
|
|
432
|
+
}
|
|
433
|
+
// Convert output to Persian numerals if language is "fa"
|
|
434
|
+
if (language === 'fa') {
|
|
435
|
+
out = out
|
|
436
|
+
.replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
|
|
437
|
+
.replace(/,/g, '٬')
|
|
438
|
+
.replace(/\./g, '٫')
|
|
439
|
+
.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
440
|
+
return String(scaleUnits[c]);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
const formattedObject = {
|
|
444
|
+
value: out,
|
|
445
|
+
prefix: unitPrefix,
|
|
446
|
+
postfix: unitPostfix.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
447
|
+
return String(scaleUnits[c]);
|
|
448
|
+
}),
|
|
449
|
+
sign: sign,
|
|
450
|
+
wholeNumber: wholeNumberStr.replace(thousandSeparatorRegex, ','),
|
|
451
|
+
fractionalPart: fractionalPartStr,
|
|
452
|
+
fractionalNonZeros: fractionalNonZeroStr,
|
|
453
|
+
fractionalZerosCount: orginalFractionalZeroStr.length,
|
|
454
|
+
};
|
|
455
|
+
return formattedObject;
|
|
360
456
|
}
|
|
361
|
-
unitPrefix = prefix + unitPrefix;
|
|
362
|
-
unitPostfix += postfix;
|
|
363
|
-
if (outputFormat === 'html') {
|
|
364
|
-
if (unitPrefix)
|
|
365
|
-
unitPrefix = `<${prefixMarker}>${unitPrefix}</${prefixMarker}>`;
|
|
366
|
-
if (unitPostfix)
|
|
367
|
-
unitPostfix = `<${postfixMarker}>${unitPostfix}</${postfixMarker}>`;
|
|
368
|
-
}
|
|
369
|
-
else if (outputFormat === 'markdown') {
|
|
370
|
-
if (unitPrefix)
|
|
371
|
-
unitPrefix = `${prefixMarker}${unitPrefix}${prefixMarker}`;
|
|
372
|
-
if (unitPostfix)
|
|
373
|
-
unitPostfix = `${postfixMarker}${unitPostfix}${postfixMarker}`;
|
|
374
|
-
}
|
|
375
|
-
const thousandSeparatorRegex = /\B(?=(\d{3})+(?!\d))/g;
|
|
376
|
-
const fixedDecimalZeroStr = fixedDecimalZeros
|
|
377
|
-
? '.'.padEnd(fixedDecimalZeros + 1, '0')
|
|
378
|
-
: '';
|
|
379
|
-
let out = '';
|
|
380
|
-
if (precision <= 0 || nonZeroDigits <= 0 || !fractionalNonZeroStr) {
|
|
381
|
-
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}${fixedDecimalZeroStr}${unitPostfix}`;
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
out = `${sign}${unitPrefix}${wholeNumberStr.replace(thousandSeparatorRegex, ',')}.${fractionalPartStr}${unitPostfix}`;
|
|
385
|
-
}
|
|
386
|
-
// Convert output to Persian numerals if language is "fa"
|
|
387
|
-
if (language === 'fa') {
|
|
388
|
-
out = out
|
|
389
|
-
.replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) + 1728))
|
|
390
|
-
.replace(/,/g, '٬')
|
|
391
|
-
.replace(/\./g, '٫')
|
|
392
|
-
.replace(/(K|M|B|T|Qt|Qd)/g, function (c) {
|
|
393
|
-
return String(scaleUnits[c]);
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
return out;
|
|
397
457
|
}
|
|
398
|
-
|
|
399
|
-
exports.default = format;
|
|
458
|
+
exports.default = NumberFormatter;
|