| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of intl; | 5 part of intl; |
| 6 /** | 6 /** |
| 7 * Provides the ability to format a number in a locale-specific way. The | 7 * Provides the ability to format a number in a locale-specific way. The |
| 8 * format is specified as a pattern using a subset of the ICU formatting | 8 * format is specified as a pattern using a subset of the ICU formatting |
| 9 * patterns. | 9 * patterns. |
| 10 * | 10 * |
| 11 * 0 - A single digit | 11 * - `0` A single digit |
| 12 * # - A single digit, omitted if the value is zero | 12 * - `#` A single digit, omitted if the value is zero |
| 13 * . - Decimal separator | 13 * - `.` Decimal separator |
| 14 * - - Minus sign | 14 * - `-` Minus sign |
| 15 * , - Grouping separator | 15 * - `,` Grouping separator |
| 16 * E - Separates mantissa and expontent | 16 * - `E` Separates mantissa and expontent |
| 17 * + - Before an exponent, indicates it should be prefixed with a plus sign. | 17 * - `+` - Before an exponent, indicates it should be prefixed with a plus sign. |
| 18 * % - In prefix or suffix, multiply by 100 and show as percentage | 18 * - `%` - In prefix or suffix, multiply by 100 and show as percentage |
| 19 * \u2030 - In prefix or suffix, multiply by 1000 and show as per mille | 19 * - `‰ (\u2030)` In prefix or suffix, multiply by 1000 and show as per mille |
| 20 * \u00A4 - Currency sign, replaced by currency name | 20 * - `¤ (\u00A4)` Currency sign, replaced by currency name |
| 21 * ' - Used to quote special characters | 21 * - `'` Used to quote special characters |
| 22 * ; - Used to separate the positive and negative patterns if both are present | 22 * - `;` Used to separate the positive and negative patterns if both are present |
| 23 * | 23 * |
| 24 * For example, | 24 * For example, |
| 25 * var f = new NumberFormat("###.0#", "en_US"); | 25 * var f = new NumberFormat("###.0#", "en_US"); |
| 26 * print(f.format(12.345)); | 26 * print(f.format(12.345)); |
| 27 * ==> 12.34 | 27 * ==> 12.34 |
| 28 * If the locale is not specified, it will default to the current locale. If | 28 * If the locale is not specified, it will default to the current locale. If |
| 29 * the format is not specified it will print in a basic format with at least | 29 * the format is not specified it will print in a basic format with at least |
| 30 * one integer digit and three fraction digits. | 30 * one integer digit and three fraction digits. |
| 31 * | 31 * |
| 32 * There are also standard patterns available via the special constructors. e.g. | 32 * There are also standard patterns available via the special constructors. e.g. |
| 33 * var symbols = new NumberFormat.percentFormat("ar"); | 33 * var symbols = new NumberFormat.percentFormat("ar"); |
| 34 * There are four such constructors: decimalFormat, percentFormat, | 34 * There are four such constructors: decimalFormat, percentFormat, |
| 35 * scientificFormat and currencyForamt. However, at the moment, | 35 * scientificFormat and currencyFormat. However, at the moment, |
| 36 * scientificFormat prints only as equivalent to "#E0" and does not take | 36 * scientificFormat prints only as equivalent to "#E0" and does not take |
| 37 * into account significant digits. currencyFormat will always use the name | 37 * into account significant digits. currencyFormat will always use the name |
| 38 * of the currency rather than the symbol. | 38 * of the currency rather than the symbol. |
| 39 */ | 39 */ |
| 40 class NumberFormat { | 40 class NumberFormat { |
| 41 /** Variables to determine how number printing behaves. */ | 41 /** Variables to determine how number printing behaves. */ |
| 42 // TODO(alanknight): If these remain as variables and are set based on the | 42 // TODO(alanknight): If these remain as variables and are set based on the |
| 43 // pattern, can we make them final? | 43 // pattern, can we make them final? |
| 44 String _negativePrefix = '-'; | 44 String _negativePrefix = '-'; |
| 45 String _positivePrefix = ''; | 45 String _positivePrefix = ''; |
| 46 String _negativeSuffix = ''; | 46 String _negativeSuffix = ''; |
| 47 String _positiveSuffix = ''; | 47 String _positiveSuffix = ''; |
| 48 /** | 48 /** |
| 49 * How many numbers in a group when using punctuation to group digits in | 49 * How many numbers in a group when using punctuation to group digits in |
| 50 * large numbers. e.g. in en_US: "1,000,000" has a grouping size of 3 digits | 50 * large numbers. e.g. in en_US: "1,000,000" has a grouping size of 3 digits |
| 51 * between commas. | 51 * between commas. |
| 52 */ | 52 */ |
| 53 int _groupingSize = 3; | 53 int _groupingSize = 3; |
| 54 bool _decimalSeparatorAlwaysShown = false; | 54 bool _decimalSeparatorAlwaysShown = false; |
| 55 bool _useSignForPositiveExponent = false; | 55 bool _useSignForPositiveExponent = false; |
| 56 bool _useExponentialNotation = false; | 56 bool _useExponentialNotation = false; |
| 57 | 57 |
| 58 int _maximumIntegerDigits = 40; | 58 int maximumIntegerDigits = 40; |
| 59 int _minimumIntegerDigits = 1; | 59 int minimumIntegerDigits = 1; |
| 60 int _maximumFractionDigits = 3; | 60 int maximumFractionDigits = 3; |
| 61 int _minimumFractionDigits = 0; | 61 int minimumFractionDigits = 0; |
| 62 int _minimumExponentDigits = 0; | 62 int minimumExponentDigits = 0; |
| 63 | 63 |
| 64 int _multiplier = 1; | 64 int _multiplier = 1; |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * Stores the pattern used to create this format. This isn't used, but | 67 * Stores the pattern used to create this format. This isn't used, but |
| 68 * is helpful in debugging. | 68 * is helpful in debugging. |
| 69 */ | 69 */ |
| 70 String _pattern; | 70 String _pattern; |
| 71 /** | |
| 72 * Set the maximum digits printed to the left of the decimal point. | |
| 73 * Normally this is computed from the pattern, but it's exposed here for | |
| 74 * testing purposes and for rare cases where you want to force it explicitly. | |
| 75 */ | |
| 76 void setMaximumIntegerDigits(int max) { | |
| 77 _maximumIntegerDigits = max; | |
| 78 } | |
| 79 | |
| 80 /** | |
| 81 * Set the minimum number of digits printed to the left of the decimal point. | |
| 82 * Normally this is computed from the pattern, but it's exposed here for | |
| 83 * testing purposes and for rare cases where you want to force it explicitly. | |
| 84 */ | |
| 85 void setMinimumIntegerDigits(int min) { | |
| 86 _minimumIntegerDigits = min; | |
| 87 } | |
| 88 | |
| 89 /** | |
| 90 * Set the maximum number of digits printed to the right of the decimal point. | |
| 91 * Normally this is computed from the pattern, but it's exposed here for | |
| 92 * testing purposes and for rare cases where you want to force it explicitly. | |
| 93 */ | |
| 94 void setMaximumFractionDigits(int max) { | |
| 95 _maximumFractionDigits = max; | |
| 96 } | |
| 97 | |
| 98 /** | |
| 99 * Set the minimum digits printed to the left of the decimal point. | |
| 100 * Normally this is computed from the pattern, but it's exposed here for | |
| 101 * testing purposes and for rare cases where you want to force it explicitly. | |
| 102 */ | |
| 103 void setMinimumFractionDigits(int max) { | |
| 104 _minimumFractionDigits = max; | |
| 105 } | |
| 106 | 71 |
| 107 /** The locale in which we print numbers. */ | 72 /** The locale in which we print numbers. */ |
| 108 final String _locale; | 73 final String _locale; |
| 109 | 74 |
| 110 /** Caches the symbols used for our locale. */ | 75 /** Caches the symbols used for our locale. */ |
| 111 NumberSymbols _symbols; | 76 NumberSymbols _symbols; |
| 112 | 77 |
| 113 /** | 78 /** |
| 114 * Transient internal state in which to build up the result of the format | 79 * Transient internal state in which to build up the result of the format |
| 115 * operation. We can have this be just an instance variable because Dart is | 80 * operation. We can have this be just an instance variable because Dart is |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 void _formatExponential(num number) { | 174 void _formatExponential(num number) { |
| 210 if (number == 0.0) { | 175 if (number == 0.0) { |
| 211 _formatFixed(number); | 176 _formatFixed(number); |
| 212 _formatExponent(0); | 177 _formatExponent(0); |
| 213 return; | 178 return; |
| 214 } | 179 } |
| 215 | 180 |
| 216 var exponent = (log(number) / log(10)).floor(); | 181 var exponent = (log(number) / log(10)).floor(); |
| 217 var mantissa = number / pow(10.0, exponent); | 182 var mantissa = number / pow(10.0, exponent); |
| 218 | 183 |
| 219 var minIntDigits = _minimumIntegerDigits; | 184 var minIntDigits = minimumIntegerDigits; |
| 220 if (_maximumIntegerDigits > 1 && | 185 if (maximumIntegerDigits > 1 && |
| 221 _maximumIntegerDigits > _minimumIntegerDigits) { | 186 maximumIntegerDigits > minimumIntegerDigits) { |
| 222 // A repeating range is defined; adjust to it as follows. | 187 // A repeating range is defined; adjust to it as follows. |
| 223 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; | 188 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; |
| 224 // -3,-4,-5=>-6, etc. This takes into account that the | 189 // -3,-4,-5=>-6, etc. This takes into account that the |
| 225 // exponent we have here is off by one from what we expect; | 190 // exponent we have here is off by one from what we expect; |
| 226 // it is for the format 0.MMMMMx10^n. | 191 // it is for the format 0.MMMMMx10^n. |
| 227 while ((exponent % _maximumIntegerDigits) != 0) { | 192 while ((exponent % maximumIntegerDigits) != 0) { |
| 228 mantissa *= 10; | 193 mantissa *= 10; |
| 229 exponent--; | 194 exponent--; |
| 230 } | 195 } |
| 231 minIntDigits = 1; | 196 minIntDigits = 1; |
| 232 } else { | 197 } else { |
| 233 // No repeating range is defined, use minimum integer digits. | 198 // No repeating range is defined, use minimum integer digits. |
| 234 if (_minimumIntegerDigits < 1) { | 199 if (minimumIntegerDigits < 1) { |
| 235 exponent++; | 200 exponent++; |
| 236 mantissa /= 10; | 201 mantissa /= 10; |
| 237 } else { | 202 } else { |
| 238 exponent -= _minimumIntegerDigits - 1; | 203 exponent -= minimumIntegerDigits - 1; |
| 239 mantissa *= pow(10, _minimumIntegerDigits - 1); | 204 mantissa *= pow(10, minimumIntegerDigits - 1); |
| 240 } | 205 } |
| 241 } | 206 } |
| 242 _formatFixed(mantissa); | 207 _formatFixed(mantissa); |
| 243 _formatExponent(exponent); | 208 _formatExponent(exponent); |
| 244 } | 209 } |
| 245 | 210 |
| 246 /** | 211 /** |
| 247 * Format the exponent portion, e.g. in "1.3e-5" the "e-5". | 212 * Format the exponent portion, e.g. in "1.3e-5" the "e-5". |
| 248 */ | 213 */ |
| 249 void _formatExponent(num exponent) { | 214 void _formatExponent(num exponent) { |
| 250 _add(symbols.EXP_SYMBOL); | 215 _add(symbols.EXP_SYMBOL); |
| 251 if (exponent < 0) { | 216 if (exponent < 0) { |
| 252 exponent = -exponent; | 217 exponent = -exponent; |
| 253 _add(symbols.MINUS_SIGN); | 218 _add(symbols.MINUS_SIGN); |
| 254 } else if (_useSignForPositiveExponent) { | 219 } else if (_useSignForPositiveExponent) { |
| 255 _add(symbols.PLUS_SIGN); | 220 _add(symbols.PLUS_SIGN); |
| 256 } | 221 } |
| 257 _pad(_minimumExponentDigits, exponent.toString()); | 222 _pad(minimumExponentDigits, exponent.toString()); |
| 258 } | 223 } |
| 259 | 224 |
| 260 /** Used to test if we have exceeded Javascript integer limits. */ | 225 /** Used to test if we have exceeded Javascript integer limits. */ |
| 261 final _maxInt = pow(2, 52); | 226 final _maxInt = pow(2, 52); |
| 262 | 227 |
| 263 /** | 228 /** |
| 264 * Format the basic number portion, inluding the fractional digits. | 229 * Format the basic number portion, inluding the fractional digits. |
| 265 */ | 230 */ |
| 266 void _formatFixed(num number) { | 231 void _formatFixed(num number) { |
| 267 // Very fussy math to get integer and fractional parts. | 232 // Very fussy math to get integer and fractional parts. |
| 268 var power = pow(10, _maximumFractionDigits); | 233 var power = pow(10, maximumFractionDigits); |
| 269 var shiftedNumber = (number * power); | 234 var shiftedNumber = (number * power); |
| 270 // We must not roundToDouble() an int or it will lose precision. We must not | 235 // We must not roundToDouble() an int or it will lose precision. We must not |
| 271 // round() a large double or it will take its loss of precision and | 236 // round() a large double or it will take its loss of precision and |
| 272 // preserve it in an int, which we will then print to the right | 237 // preserve it in an int, which we will then print to the right |
| 273 // of the decimal place. Therefore, only roundToDouble if we are already | 238 // of the decimal place. Therefore, only roundToDouble if we are already |
| 274 // a double. | 239 // a double. |
| 275 if (shiftedNumber is double) { | 240 if (shiftedNumber is double) { |
| 276 shiftedNumber = shiftedNumber.roundToDouble(); | 241 shiftedNumber = shiftedNumber.roundToDouble(); |
| 277 } | 242 } |
| 278 var intValue, fracValue; | 243 var intValue, fracValue; |
| 279 if (shiftedNumber.isInfinite) { | 244 if (shiftedNumber.isInfinite) { |
| 280 intValue = number.toInt(); | 245 intValue = number.toInt(); |
| 281 fracValue = 0; | 246 fracValue = 0; |
| 282 } else { | 247 } else { |
| 283 intValue = shiftedNumber.round() ~/ power; | 248 intValue = shiftedNumber.round() ~/ power; |
| 284 fracValue = (shiftedNumber - intValue * power).floor(); | 249 fracValue = (shiftedNumber - intValue * power).floor(); |
| 285 } | 250 } |
| 286 var fractionPresent = _minimumFractionDigits > 0 || fracValue > 0; | 251 var fractionPresent = minimumFractionDigits > 0 || fracValue > 0; |
| 287 | 252 |
| 288 // If the int part is larger than 2^52 and we're on Javascript (so it's | 253 // If the int part is larger than 2^52 and we're on Javascript (so it's |
| 289 // really a float) it will lose precision, so pad out the rest of it | 254 // really a float) it will lose precision, so pad out the rest of it |
| 290 // with zeros. Check for Javascript by seeing if an integer is double. | 255 // with zeros. Check for Javascript by seeing if an integer is double. |
| 291 var paddingDigits = new StringBuffer(); | 256 var paddingDigits = new StringBuffer(); |
| 292 if (1 is double && intValue > _maxInt) { | 257 if (1 is double && intValue > _maxInt) { |
| 293 var howManyDigitsTooBig = (log(intValue) / LN10).ceil() - 16; | 258 var howManyDigitsTooBig = (log(intValue) / LN10).ceil() - 16; |
| 294 var divisor = pow(10, howManyDigitsTooBig).round(); | 259 var divisor = pow(10, howManyDigitsTooBig).round(); |
| 295 for (var each in new List(howManyDigitsTooBig.toInt())) { | 260 for (var each in new List(howManyDigitsTooBig.toInt())) { |
| 296 paddingDigits.write(symbols.ZERO_DIGIT); | 261 paddingDigits.write(symbols.ZERO_DIGIT); |
| 297 } | 262 } |
| 298 intValue = (intValue / divisor).truncate(); | 263 intValue = (intValue / divisor).truncate(); |
| 299 } | 264 } |
| 300 var integerDigits = "${intValue}${paddingDigits}".codeUnits; | 265 var integerDigits = "${intValue}${paddingDigits}".codeUnits; |
| 301 var digitLength = integerDigits.length; | 266 var digitLength = integerDigits.length; |
| 302 | 267 |
| 303 if (_hasPrintableIntegerPart(intValue)) { | 268 if (_hasPrintableIntegerPart(intValue)) { |
| 304 _pad(_minimumIntegerDigits - digitLength); | 269 _pad(minimumIntegerDigits - digitLength); |
| 305 for (var i = 0; i < digitLength; i++) { | 270 for (var i = 0; i < digitLength; i++) { |
| 306 _addDigit(integerDigits[i]); | 271 _addDigit(integerDigits[i]); |
| 307 _group(digitLength, i); | 272 _group(digitLength, i); |
| 308 } | 273 } |
| 309 } else if (!fractionPresent) { | 274 } else if (!fractionPresent) { |
| 310 // If neither fraction nor integer part exists, just print zero. | 275 // If neither fraction nor integer part exists, just print zero. |
| 311 _addZero(); | 276 _addZero(); |
| 312 } | 277 } |
| 313 | 278 |
| 314 _decimalSeparator(fractionPresent); | 279 _decimalSeparator(fractionPresent); |
| 315 _formatFractionPart((fracValue + power).toString()); | 280 _formatFractionPart((fracValue + power).toString()); |
| 316 } | 281 } |
| 317 | 282 |
| 318 /** | 283 /** |
| 319 * Format the part after the decimal place in a fixed point number. | 284 * Format the part after the decimal place in a fixed point number. |
| 320 */ | 285 */ |
| 321 void _formatFractionPart(String fractionPart) { | 286 void _formatFractionPart(String fractionPart) { |
| 322 var fractionCodes = fractionPart.codeUnits; | 287 var fractionCodes = fractionPart.codeUnits; |
| 323 var fractionLength = fractionPart.length; | 288 var fractionLength = fractionPart.length; |
| 324 while(fractionCodes[fractionLength - 1] == _zero && | 289 while(fractionCodes[fractionLength - 1] == _zero && |
| 325 fractionLength > _minimumFractionDigits + 1) { | 290 fractionLength > minimumFractionDigits + 1) { |
| 326 fractionLength--; | 291 fractionLength--; |
| 327 } | 292 } |
| 328 for (var i = 1; i < fractionLength; i++) { | 293 for (var i = 1; i < fractionLength; i++) { |
| 329 _addDigit(fractionCodes[i]); | 294 _addDigit(fractionCodes[i]); |
| 330 } | 295 } |
| 331 } | 296 } |
| 332 | 297 |
| 333 /** Print the decimal separator if appropriate. */ | 298 /** Print the decimal separator if appropriate. */ |
| 334 void _decimalSeparator(bool fractionPresent) { | 299 void _decimalSeparator(bool fractionPresent) { |
| 335 if (_decimalSeparatorAlwaysShown || fractionPresent) { | 300 if (_decimalSeparatorAlwaysShown || fractionPresent) { |
| 336 _add(symbols.DECIMAL_SEP); | 301 _add(symbols.DECIMAL_SEP); |
| 337 } | 302 } |
| 338 } | 303 } |
| 339 | 304 |
| 340 /** | 305 /** |
| 341 * Return true if we have a main integer part which is printable, either | 306 * Return true if we have a main integer part which is printable, either |
| 342 * because we have digits left of the decimal point, or because there are | 307 * because we have digits left of the decimal point, or because there are |
| 343 * a minimum number of printable digits greater than 1. | 308 * a minimum number of printable digits greater than 1. |
| 344 */ | 309 */ |
| 345 bool _hasPrintableIntegerPart(int intValue) { | 310 bool _hasPrintableIntegerPart(int intValue) { |
| 346 return intValue > 0 || _minimumIntegerDigits > 0; | 311 return intValue > 0 || minimumIntegerDigits > 0; |
| 347 } | 312 } |
| 348 | 313 |
| 349 /** | 314 /** |
| 350 * Create a new empty buffer. See comment on [_buffer] variable for why | 315 * Create a new empty buffer. See comment on [_buffer] variable for why |
| 351 * we have it as an instance variable rather than passing it on the stack. | 316 * we have it as an instance variable rather than passing it on the stack. |
| 352 */ | 317 */ |
| 353 void _newBuffer() { _buffer = new StringBuffer(); } | 318 void _newBuffer() { _buffer = new StringBuffer(); } |
| 354 | 319 |
| 355 /** A group of methods that provide support for writing digits and other | 320 /** A group of methods that provide support for writing digits and other |
| 356 * required characters into [_buffer] easily. | 321 * required characters into [_buffer] easily. |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 | 565 |
| 601 // Do syntax checking on the digits. | 566 // Do syntax checking on the digits. |
| 602 if (decimalPos < 0 && digitRightCount > 0 || | 567 if (decimalPos < 0 && digitRightCount > 0 || |
| 603 decimalPos >= 0 && (decimalPos < digitLeftCount || | 568 decimalPos >= 0 && (decimalPos < digitLeftCount || |
| 604 decimalPos > digitLeftCount + zeroDigitCount) || | 569 decimalPos > digitLeftCount + zeroDigitCount) || |
| 605 groupingCount == 0) { | 570 groupingCount == 0) { |
| 606 throw new FormatException('Malformed pattern "${pattern.input}"'); | 571 throw new FormatException('Malformed pattern "${pattern.input}"'); |
| 607 } | 572 } |
| 608 var totalDigits = digitLeftCount + zeroDigitCount + digitRightCount; | 573 var totalDigits = digitLeftCount + zeroDigitCount + digitRightCount; |
| 609 | 574 |
| 610 format._maximumFractionDigits = | 575 format.maximumFractionDigits = |
| 611 decimalPos >= 0 ? totalDigits - decimalPos : 0; | 576 decimalPos >= 0 ? totalDigits - decimalPos : 0; |
| 612 if (decimalPos >= 0) { | 577 if (decimalPos >= 0) { |
| 613 format._minimumFractionDigits = | 578 format.minimumFractionDigits = |
| 614 digitLeftCount + zeroDigitCount - decimalPos; | 579 digitLeftCount + zeroDigitCount - decimalPos; |
| 615 if (format._minimumFractionDigits < 0) { | 580 if (format.minimumFractionDigits < 0) { |
| 616 format._minimumFractionDigits = 0; | 581 format.minimumFractionDigits = 0; |
| 617 } | 582 } |
| 618 } | 583 } |
| 619 | 584 |
| 620 // The effectiveDecimalPos is the position the decimal is at or would be at | 585 // The effectiveDecimalPos is the position the decimal is at or would be at |
| 621 // if there is no decimal. Note that if decimalPos<0, then digitTotalCount | 586 // if there is no decimal. Note that if decimalPos<0, then digitTotalCount |
| 622 // == digitLeftCount + zeroDigitCount. | 587 // == digitLeftCount + zeroDigitCount. |
| 623 var effectiveDecimalPos = decimalPos >= 0 ? decimalPos : totalDigits; | 588 var effectiveDecimalPos = decimalPos >= 0 ? decimalPos : totalDigits; |
| 624 format._minimumIntegerDigits = effectiveDecimalPos - digitLeftCount; | 589 format.minimumIntegerDigits = effectiveDecimalPos - digitLeftCount; |
| 625 if (format._useExponentialNotation) { | 590 if (format._useExponentialNotation) { |
| 626 format._maximumIntegerDigits = | 591 format.maximumIntegerDigits = |
| 627 digitLeftCount + format._minimumIntegerDigits; | 592 digitLeftCount + format.minimumIntegerDigits; |
| 628 | 593 |
| 629 // In exponential display, we need to at least show something. | 594 // In exponential display, we need to at least show something. |
| 630 if (format._maximumFractionDigits == 0 && | 595 if (format.maximumFractionDigits == 0 && |
| 631 format._minimumIntegerDigits == 0) { | 596 format.minimumIntegerDigits == 0) { |
| 632 format._minimumIntegerDigits = 1; | 597 format.minimumIntegerDigits = 1; |
| 633 } | 598 } |
| 634 } | 599 } |
| 635 | 600 |
| 636 format._groupingSize = max(0, groupingCount); | 601 format._groupingSize = max(0, groupingCount); |
| 637 format._decimalSeparatorAlwaysShown = decimalPos == 0 || | 602 format._decimalSeparatorAlwaysShown = decimalPos == 0 || |
| 638 decimalPos == totalDigits; | 603 decimalPos == totalDigits; |
| 639 | 604 |
| 640 return trunk.toString(); | 605 return trunk.toString(); |
| 641 } | 606 } |
| 642 | 607 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 678 } | 643 } |
| 679 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; | 644 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; |
| 680 break; | 645 break; |
| 681 case _PATTERN_EXPONENT: | 646 case _PATTERN_EXPONENT: |
| 682 trunk.write(ch); | 647 trunk.write(ch); |
| 683 if (format._useExponentialNotation) { | 648 if (format._useExponentialNotation) { |
| 684 throw new FormatException( | 649 throw new FormatException( |
| 685 'Multiple exponential symbols in pattern "$pattern"'); | 650 'Multiple exponential symbols in pattern "$pattern"'); |
| 686 } | 651 } |
| 687 format._useExponentialNotation = true; | 652 format._useExponentialNotation = true; |
| 688 format._minimumExponentDigits = 0; | 653 format.minimumExponentDigits = 0; |
| 689 | 654 |
| 690 // exponent pattern can have a optional '+'. | 655 // exponent pattern can have a optional '+'. |
| 691 pattern.moveNext(); | 656 pattern.moveNext(); |
| 692 var nextChar = pattern.current; | 657 var nextChar = pattern.current; |
| 693 if (nextChar == _PATTERN_PLUS) { | 658 if (nextChar == _PATTERN_PLUS) { |
| 694 trunk.write(pattern.current); | 659 trunk.write(pattern.current); |
| 695 pattern.moveNext(); | 660 pattern.moveNext(); |
| 696 format._useSignForPositiveExponent = true; | 661 format._useSignForPositiveExponent = true; |
| 697 } | 662 } |
| 698 | 663 |
| 699 // Use lookahead to parse out the exponential part | 664 // Use lookahead to parse out the exponential part |
| 700 // of the pattern, then jump into phase 2. | 665 // of the pattern, then jump into phase 2. |
| 701 while (pattern.current == _PATTERN_ZERO_DIGIT) { | 666 while (pattern.current == _PATTERN_ZERO_DIGIT) { |
| 702 trunk.write(pattern.current); | 667 trunk.write(pattern.current); |
| 703 pattern.moveNext(); | 668 pattern.moveNext(); |
| 704 format._minimumExponentDigits++; | 669 format.minimumExponentDigits++; |
| 705 } | 670 } |
| 706 | 671 |
| 707 if ((digitLeftCount + zeroDigitCount) < 1 || | 672 if ((digitLeftCount + zeroDigitCount) < 1 || |
| 708 format._minimumExponentDigits < 1) { | 673 format.minimumExponentDigits < 1) { |
| 709 throw new FormatException( | 674 throw new FormatException( |
| 710 'Malformed exponential pattern "$pattern"'); | 675 'Malformed exponential pattern "$pattern"'); |
| 711 } | 676 } |
| 712 return false; | 677 return false; |
| 713 default: | 678 default: |
| 714 return false; | 679 return false; |
| 715 } | 680 } |
| 716 trunk.write(ch); | 681 trunk.write(ch); |
| 717 pattern.moveNext(); | 682 pattern.moveNext(); |
| 718 return true; | 683 return true; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 749 String input; | 714 String input; |
| 750 var index = -1; | 715 var index = -1; |
| 751 inBounds(i) => i >= 0 && i < input.length; | 716 inBounds(i) => i >= 0 && i < input.length; |
| 752 _StringIterator(this.input); | 717 _StringIterator(this.input); |
| 753 String get current => inBounds(index) ? input[index] : null; | 718 String get current => inBounds(index) ? input[index] : null; |
| 754 | 719 |
| 755 bool moveNext() => inBounds(++index); | 720 bool moveNext() => inBounds(++index); |
| 756 String get peek => inBounds(index + 1) ? input[index + 1] : null; | 721 String get peek => inBounds(index + 1) ? input[index + 1] : null; |
| 757 Iterator<String> get iterator => this; | 722 Iterator<String> get iterator => this; |
| 758 } | 723 } |
| OLD | NEW |