Commit 86b8de4b authored by Zéfling's avatar Zéfling 🎨
Browse files

Réécriture complète du parseur de nombre

parent 6af9362f
......@@ -7,68 +7,115 @@
* - language : langue de formatage (défaut : langue du navigateur)
* @return la chaine formatée
*/
Number.prototype.formatByPattern = function(pattern, params) {
Number.prototype._formatByPattern = function(pattern, params) {
var params = typeof(params) === 'object' ? params : {},
groupingSize = 0,
decimalSize = 0,
lg = params.lg || navigator.language,
dot = params.dot,
space = params.space;
format = {
groupingSize : 0,
zeroDigitSize : 0,
decimalSize : 0,
decimalZeroSize : 0,
unit : undefined,
dot : params.dot,
space : params.space
},
lg = params.lg || navigator.language;
if(!pattern) {
// partern par défaut
pattern = '#,###';
}
var match = pattern.match(/(#*,|)([#0]+)(?:\.(0+|#+|)|)/);
if(match) {
groupingSize = match[1] !== '' ? match[2].length : 0;
decimalSize = match[3] ? match[3].length : 0;
var match = pattern.match(/\s*(?:((?:[#,]*)(?:[0,]*))(?:(?:\.([0 ]*#*))|))((?:\s*\%)|)\s*$/);
if(match && match[0] === pattern) {
var number = match[1];
var decimal = match[2] ? match[2].replace(/\s/, '').match(/^(0*)#*/) : null;
format.unit = match[3];
// digit grouping
format.groupingSize = number.match(/,?([#]*[0]*)$/)[1].length;
format.zeroDigitSize = number.match(/[,0]*$/)[0].replace(/,/g, '').length;
// decimal
if (decimal) {
format.decimalSize = decimal[0].length;
format.decimalZeroSize = decimal[1].length;
}
}
else {
throw 'patten error : '+pattern;
}
if (dot === undefined) {
if (format.dot === undefined) {
switch (lg) {
case 'en' : dot = '.'; break;
case 'fr' : dot = ','; break;
case 'en' : format.dot = '.'; break;
case 'fr' : format.dot = ','; break;
}
}
if (space === undefined) {
if (format.space === undefined) {
switch (lg) {
case 'en' : space = ','; break;
case 'fr' : space = "\u00A0"; break;
case 'en' : format.space = ','; break;
case 'fr' : format.space = "\u00A0"; break;
}
}
return this.format(groupingSize, decimalSize, dot, space);
return this._format(format);
}
/**
* formatage suivant paramètre
* @param groupingSize séparateur de lisiblité (0 = aucun)
* @param decimalSize nombre de décimales affichées
* @param dot forme du séparateur de décimales (défaut : '.')
* @param space sparateur de millier (ou autre) (défaut : '')
* @param format
* - groupingSize : séparateur de lisiblité (0 = aucun)
* - zeroDigitSize : nombre de chiffres minimums
* - decimalSize : nombre de décimales affichées
* - decimalZeroSize : nombre de chiffres minimums en décimal
* - dot : forme du séparateur de décimales (défaut : '.')
* - space : sparateur de millier (ou autre) (défaut : '')
* - unit : rien ou %
* @return la chaine formatée
*/
Number.prototype.format = function(groupingSize, decimalSize, dot, space) {
var val = new String(this),
Number.prototype._format = function(format) {
var val,
valueAsStr,
result = '',
valueAsStr = val.match(/(-|)(\d*)(?:.(\d*))?/);
format = !format ? {} : format,
unit = format.unit||'';
switch (unit.trim()) {
case '%':
val = new String(this * 100);
break;
default :
val = new String(this);
}
valueAsStr = val.match(/(-|)(\d*)(?:.(\d*))?/);
if (format.zeroDigitSize > 0) {
valueAsStr[2] = valueAsStr[2].padLeft(format.zeroDigitSize, '0');
}
// ajoute des espaces
var entier = groupingSize && groupingSize > 0
? valueAsStr[2].replace(new RegExp('(?=(?:\\d{' + groupingSize + '})+$)(?!^)', 'g'), space !== undefined ? space : '')
: valueAsStr[2];
var entier = format.space !== undefined && format.groupingSize && format.groupingSize > 0
? valueAsStr[2].replace(new RegExp('(?=(?:\\d{' + format.groupingSize + '})+$)(?!^)', 'g'), format.space)
: valueAsStr[2];
// formatage des décimales
var decimal = '';
if(decimalSize && decimalSize > 0) {
decimal = valueAsStr[3];
if(!decimal) {
decimal = '0';
if(format.decimalSize && format.decimalSize > 0) {
decimal = new String(parseFloat('.' + (valueAsStr[3]||'0'))._roundDecimal(format.decimalSize)).replace('0.', '');
if (decimal == '0') {
decimal = '';
}
if (format.decimalZeroSize > 0) {
decimal = decimal.padRight(format.decimalZeroSize, '0');
}
if (decimal !== '') {
decimal = format.dot + decimal;
}
// si supérieur au nombre de zéro, on découpe, sinon on en ajoute à la fin
decimal = (dot !== undefined ? dot : '.') + (decimal.length > decimalSize
? decimal.substring(0, decimalSize)
: decimal.padRight(decimalSize, '0'));
}
return valueAsStr[1] + entier + decimal;
}
\ No newline at end of file
return valueAsStr[1] + entier + decimal + unit;
}
/**
* arrondi à la décimale choisie
* @param decimalSize nombre de chiffres après la virgule
* @return la chaine formatée
*/
Number.prototype._roundDecimal = function(decimalSize) {
var pow = Math.pow(10, decimalSize);
return Math.round(this * pow) / pow;
}
\ No newline at end of file
......@@ -35,12 +35,12 @@ Formatter.number = function (val, vals, arg) {
}
// recupération de la langue : #,##0:fr
var params = {},
match = arg.match(/[#0]:(([a-z]{2})(-[A-Z]{2})?)/);
if(match && match[1]) {
params.lg = match[2];
params.local = match[1];
match = arg.match(/([,#0. ]*)(?::(([a-z]{2})(-[A-Z]{2})?)|)/);
if(match && match[2]) {
params.lg = match[3];
params.local = match[2];
}
return val.formatByPattern(arg, params);
return val._formatByPattern(match[1], params);
}
/**
......
......@@ -16,7 +16,7 @@ Test.equals = function (test, equals, message) {
ok = false;
}
b.classList.add(ok ? 'ok' : 'ko');
b.title = message + (ok ? ' #ok' : ' #ko : "' + result + '" != "' + equals + '"' ) + ' (' + (Math.round((time2 - time1) * 10000) / 10000).formatByPattern('#,###.000') + 'ms)';
b.title = message + (ok ? ' #ok' : ' #ko : "' + result + '" != "' + equals + '"' ) + ' (' + (Math.round((time2 - time1) * 10000) / 10000) + 'ms)';
document.body.appendChild(b);
};
......@@ -33,7 +33,7 @@ Test.error = function (test) {
message = e;
}
b.classList.add(ok ? 'ok' : 'ko');
b.title = test + (ok ? ' #ko : ' + message : ' #ok : "' + result + '"' ) + ' (' + (Math.round((time2 - time1) * 10000) / 10000).formatByPattern('#,###.000') + 'ms)';
b.title = test + (ok ? ' #ko : ' + message : ' #ok : "' + result + '"' ) + ' (' + (Math.round((time2 - time1) * 10000) / 10000) + 'ms)';
document.body.appendChild(b);
};
......@@ -137,34 +137,40 @@ window.onload = function(){
Test.equals("new Date('2016-01-03').getWeek(0)", 2, 'week : 2016-01-03 → 53');
Test.equals("new Date('2016-01-04').getWeek(0)", 2, 'week : 2016-01-04 → 1');
Test.title("Number.formatByPattern()");
Test.equals("new Number(1).formatByPattern('#,###', {lg : 'fr'})", '1', '1 + #,### → 1');
Test.equals("new Number(1).formatByPattern('#,##0', {lg : 'fr'})", '1', '1 + #,##0 → 1');
Test.equals("new Number(1).formatByPattern('#,#00', {lg : 'fr'})", '01', '1 + #,#00 → 01');
Test.equals("new Number(1).formatByPattern('#,###.0', {lg : 'fr'})", '1,0', '1 + #,###.0 → 1,0');
Test.equals("new Number(1).formatByPattern('#,###.00', {lg : 'fr'})", '1,00', '1 + #,###.000 → 1,00');
Test.equals("new Number(1).formatByPattern('#,###.0', {lg : 'en'})", '1.0', '1 + #,### → 1.0');
Test.equals("new Number(1).formatByPattern('#,###.00', {lg : 'en'})", '1.00', '1 + #,### → 1.00');
Test.equals("new Number(1).formatByPattern('#,###.##', {lg : 'en'})", '1', '1 + #,### → 1');
Test.equals("new Number(1.1).formatByPattern('#,###.##', {lg : 'en'})", '1.1', '1 + #,### → 1.1');
Test.equals("new Number(1000 ).formatByPattern('#,###', {lg : 'fr'})", '1\u00A0000', '1000 + #,### → 1\u00A0000');
Test.equals("new Number(1000000).formatByPattern('#,###', {lg : 'fr'})", '1\u00A0000\u00A0000', '1000000 + #,### → 1\u00A0000\u00A0000');
Test.equals("new Number(1000 ).formatByPattern('#,####', {lg : 'fr'})", '1000', '1000 + #,### → 1000');
Test.equals("new Number(1000000).formatByPattern('#,####', {lg : 'fr'})", '100\u00A00000', '1000000 + #,### → 100\u00A00000');
Test.equals("new Number(123456789.987654321).formatByPattern('#,###.00', {lg : 'en'})", '123,456,789.98', '123456789.987654321 + #,###.00 → 123,456,789.98');
Test.equals("new Number(123456789.987654321).formatByPattern('#,###.##', {lg : 'en'})", '123,456,789.98', '123456789.987654321 + #,###.## → 123,456,789.98');
Test.equals("new Number(123.123).formatByPattern('0000.00', {lg : 'fr'})", '0123,12', '123.123 + #,### → 0123,12');
Test.equals("new Number(123.123).formatByPattern('0000.0###', {lg : 'fr'})", '0123,123', '123.123 + #,### → 0123,123');
Test.equals("new Number(123.123).formatByPattern('0000.0000', {lg : 'fr'})", '0123,1230', '123.123 + #,### → 0123,1230');
Test.equals("new Number(123.103).formatByPattern('0000.##', {lg : 'fr'})", '0123,1', '123.103 + #,### → 0123,1');
Test.equals("new Number(123.103).formatByPattern('#000.##', {lg : 'fr'})", '123,1', '123.103 + #,### → 123,1');
Test.equals("new Number(123.103).formatByPattern('00,000,000.00',{lg : 'en'})", '00,000,123.10', '123.103 + 00,000,000.00 → 00,000,123.10');
Test.equals("new Number(123.103).formatByPattern('00000,000.00', {lg : 'en'})", '00,000,123.10', '123.103 + 00000,000.00 → 00,000,123.10');
Test.equals("new Number(123.103).formatByPattern('#0,000.00', {lg : 'en'})", '0,123.10', '123.103 + #0,000.00 → 0,123.10');
Test.equals("new Number(1325123.103456).formatByPattern('0,00,000.000 00', {lg : 'en'})", '1,325,123.10346', '1325123.103456 + #0,000.00 → 1,325,123.10346');
Test.error("new Number(123.103).formatByPattern('0#000.##', {lg : 'fr'})");
Test.error("new Number(123.103).formatByPattern('0000.#0', {lg : 'fr'})");
Test.error("new Number(123.103).formatByPattern('0000.#0#', {lg : 'fr'})");
Test.title("Number._formatByPattern()");
Test.equals("new Number(1)._formatByPattern('#,###', {lg : 'fr'})", '1', '1 + #,### → 1');
Test.equals("new Number(1)._formatByPattern('#,##0', {lg : 'fr'})", '1', '1 + #,##0 → 1');
Test.equals("new Number(1)._formatByPattern('#,#00', {lg : 'fr'})", '01', '1 + #,#00 → 01');
Test.equals("new Number(1)._formatByPattern('#,###.0', {lg : 'fr'})", '1,0', '1 + #,###.0 → 1,0');
Test.equals("new Number(1)._formatByPattern('#,###.00', {lg : 'fr'})", '1,00', '1 + #,###.000 → 1,00');
Test.equals("new Number(1)._formatByPattern('#,###.0', {lg : 'en'})", '1.0', '1 + #,###.0 → 1.0');
Test.equals("new Number(1)._formatByPattern('#,###.00', {lg : 'en'})", '1.00', '1 + #,###.00 → 1.00');
Test.equals("new Number(1)._formatByPattern('#,###.##', {lg : 'en'})", '1', '1 + #,###.## → 1');
Test.equals("new Number(1.1)._formatByPattern('#,###.##', {lg : 'en'})", '1.1', '1 + #,###.## → 1.1');
Test.equals("new Number(1000 )._formatByPattern('#,###', {lg : 'fr'})", '1\u00A0000', '1000 + #,### → 1\u00A0000');
Test.equals("new Number(1000000)._formatByPattern('#,###', {lg : 'fr'})", '1\u00A0000\u00A0000', '1000000 + #,### → 1\u00A0000\u00A0000');
Test.equals("new Number(1000 )._formatByPattern('#,####', {lg : 'fr'})", '1000', '1000 + #,### → 1000');
Test.equals("new Number(1000000)._formatByPattern('#,####', {lg : 'fr'})", '100\u00A00000', '1000000 + #,### → 100\u00A00000');
Test.equals("new Number(123456789.987654321)._formatByPattern('#,###.00', {lg : 'en'})", '123,456,789.99', '123456789.987654321 + #,###.00 → 123,456,789.99');
Test.equals("new Number(123456789.987654321)._formatByPattern('#,###.##', {lg : 'en'})", '123,456,789.99', '123456789.987654321 + #,###.## → 123,456,789.99');
Test.equals("new Number(123.123)._formatByPattern('0000.00', {lg : 'fr'})", '0123,12', '123.123 + #,### → 0123,12');
Test.equals("new Number(123.123)._formatByPattern('0000.0###', {lg : 'fr'})", '0123,123', '123.123 + #,### → 0123,123');
Test.equals("new Number(123.123)._formatByPattern('0000.0000', {lg : 'fr'})", '0123,1230', '123.123 + #,### → 0123,1230');
Test.equals("new Number(123.103)._formatByPattern('0000.##', {lg : 'fr'})", '0123,1', '123.103 + #,### → 0123,1');
Test.equals("new Number(123.103)._formatByPattern('#000.##', {lg : 'fr'})", '123,1', '123.103 + #,### → 123,1');
Test.equals("new Number(123.103)._formatByPattern('00,000,000.00',{lg : 'en'})", '00,000,123.10', '123.103 + 00,000,000.00 → 00,000,123.10');
Test.equals("new Number(123.103)._formatByPattern('00000,000.00', {lg : 'en'})", '00,000,123.10', '123.103 + 00000,000.00 → 00,000,123.10');
Test.equals("new Number(123.103)._formatByPattern('#0,000.00', {lg : 'en'})", '0,123.10', '123.103 + #0,000.00 → 0,123.10');
Test.equals("new Number(1325123.103456)._formatByPattern('0,00,000.000 00', {lg : 'en'})", '1,325,123.10346', '1325123.103456 + #0,000.00 → 1,325,123.10346');
Test.equals("new Number(1)._formatByPattern('#,###%', {lg : 'fr'})", '100%', '1 + #,###% → 100%');
Test.equals("new Number(1)._formatByPattern('#,### %', {lg : 'fr'})", '100 %', '1 + #,### % → 100 %');
Test.equals("new Number(1.1)._formatByPattern('#,###.00%', {lg : 'fr'})", '110,00%', '1.1 + #,###.00% → 110,00%');
Test.equals("new Number(1.1)._formatByPattern('0,000.00%', {lg : 'en'})", '0,110.00%', '1.1 + #,###.00% → 0,110.00%');
Test.equals("new Number(1.1111)._formatByPattern('0,000.00%', {lg : 'en'})", '0,111.11%', '1.1111 + #,###.00% → 0,111.11%');
Test.error("new Number(123.103)._formatByPattern('0#000.##', {lg : 'fr'})");
Test.error("new Number(123.103)._formatByPattern('0000.#0', {lg : 'fr'})");
Test.error("new Number(123.103)._formatByPattern('0000.#0#', {lg : 'fr'})");
Test.error("new Number(123.103)._formatByPattern('0000.#0%', {lg : 'fr'})");
Test.title("String.padLeft()");
Test.equals("'1'.padLeft(1, '.')", '1', "1 + left(1, '') → 1");
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment