1. /*
  2. * @(#)DecimalFormat.java 1.51 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * @(#)DecimalFormat.java 1.51 01/11/29
  9. *
  10. * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
  11. * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
  12. *
  13. * Portions copyright (c) 1996-1998 Sun Microsystems, Inc.
  14. * All Rights Reserved.
  15. *
  16. * The original version of this source code and documentation is copyrighted
  17. * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  18. * materials are provided under terms of a License Agreement between Taligent
  19. * and Sun. This technology is protected by multiple US and International
  20. * patents. This notice and attribution to Taligent may not be removed.
  21. * Taligent is a registered trademark of Taligent, Inc.
  22. *
  23. * Permission to use, copy, modify, and distribute this software
  24. * and its documentation for NON-COMMERCIAL purposes and without
  25. * fee is hereby granted provided that this copyright notice
  26. * appears in all copies. Please refer to the file "copyright.html"
  27. * for further important copyright and licensing information.
  28. *
  29. * SUN MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  30. * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  31. * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  32. * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  33. * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  34. * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  35. *
  36. */
  37. package java.text;
  38. import java.util.ResourceBundle;
  39. import java.util.Locale;
  40. import java.io.IOException;
  41. import java.io.ObjectInputStream;
  42. import java.util.Hashtable;
  43. /**
  44. * <code>DecimalFormat</code> is a concrete subclass of <code>NumberFormat</code>
  45. * for formatting decimal numbers. This class allows for a variety
  46. * of parameters, and localization to Western, Arabic, or Indic numbers.
  47. *
  48. * <p>
  49. * Normally, you get the proper <code>NumberFormat</code> for a specific
  50. * locale (including the default locale) using one of <code>NumberFormat</code>'s
  51. * factory methods such as <code>getInstance</code>. You may then modify it
  52. * from there (after testing to make sure it is a <code>DecimalFormat</code>,
  53. * of course!)
  54. *
  55. * <p>
  56. * Either the prefixes or the suffixes must be different for
  57. * the parse to distinguish positive from negative.
  58. * Parsing will be unreliable if the digits, thousands or decimal separators
  59. * are the same, or if any of them occur in the prefixes or suffixes.
  60. *
  61. * <p>
  62. * <strong>Special cases:</strong>
  63. *
  64. * <p>
  65. * <code>NaN</code> is formatted as a single character, typically
  66. * <code>\\uFFFD</code>.
  67. *
  68. * <p>
  69. * +/-Infinity is formatted as a single character, typically <code>\\u221E</code>,
  70. * plus the positive and negative pre/suffixes.
  71. *
  72. * <p><code>Note:</code> this class is designed for common users; for very
  73. * large or small numbers, use a format that can express exponential values.
  74. * <p><strong>Example:</strong>
  75. * <blockquote>
  76. * <pre>
  77. * // normally we would have a GUI with a menu for this
  78. * Locale[] locales = NumberFormat.getAvailableLocales();
  79. *
  80. * double myNumber = -1234.56;
  81. * NumberFormat form;
  82. *
  83. * // just for fun, we print out a number with the locale number, currency
  84. * // and percent format for each locale we can.
  85. * for (int j = 0; j < 3; ++j) {
  86. * System.out.println("FORMAT");
  87. * for (int i = 0; i < locales.length; ++i) {
  88. * if (locales[i].getCountry().length() == 0) {
  89. * // skip language-only
  90. * continue;
  91. * }
  92. * System.out.print(locales[i].getDisplayName());
  93. * switch (j) {
  94. * default:
  95. * form = NumberFormat.getInstance(locales[i]); break;
  96. * case 1:
  97. * form = NumberFormat.getCurrencyInstance(locales[i]); break;
  98. * case 0:
  99. * form = NumberFormat.getPercentInstance(locales[i]); break;
  100. * }
  101. * try {
  102. * System.out.print(": " + ((DecimalFormat)form).toPattern()
  103. * + " -> " + form.format(myNumber));
  104. * } catch (IllegalArgumentException iae) { }
  105. * try {
  106. * System.out.println(" -> " + form.parse(form.format(myNumber)));
  107. * } catch (ParseException pe) { }
  108. * }
  109. * }
  110. * </pre>
  111. * </blockquote>
  112. * <strong>The following shows the structure of the pattern.</strong>
  113. * <pre>
  114. * pattern := subpattern{;subpattern}
  115. * subpattern := {prefix}integer{.fraction}{suffix}
  116. *
  117. * prefix := '\\u0000'..'\\uFFFD' - specialCharacters
  118. * suffix := '\\u0000'..'\\uFFFD' - specialCharacters
  119. * integer := '#'* '0'* '0'
  120. * fraction := '0'* '#'*
  121. *
  122. * Notation:
  123. * X* 0 or more instances of X
  124. * (X | Y) either X or Y.
  125. * X..Y any character from X up to Y, inclusive.
  126. * S - T characters in S, except those in T
  127. * </pre>
  128. * The first subpattern is for positive numbers. The second (optional)
  129. * subpattern is for negative numbers. (In both cases, ',' can occur
  130. * inside the integer portion--it is just too messy to indicate in BNF.)
  131. *
  132. * <p>
  133. * Here are the special characters used in the parts of the
  134. * subpattern, with notes on their usage.
  135. * <pre>
  136. * Symbol Meaning
  137. * 0 a digit
  138. * # a digit, zero shows as absent
  139. * . placeholder for decimal separator
  140. * , placeholder for grouping separator.
  141. * E separates mantissa and exponent for exponential formats.
  142. * ; separates formats.
  143. * - default negative prefix.
  144. * % multiply by 100 and show as percentage
  145. * \u2030 multiply by 1000 and show as per mille
  146. * \u00A4 currency sign; replaced by currency symbol; if
  147. * doubled, replaced by international currency symbol.
  148. * If present in a pattern, the monetary decimal separator
  149. * is used instead of the decimal separator.
  150. * X any other characters can be used in the prefix or suffix
  151. * ' used to quote special characters in a prefix or suffix.
  152. * </pre>
  153. * <p><strong>Notes</strong>
  154. * <p>
  155. * If there is no explicit negative subpattern, - is prefixed to the
  156. * positive form. That is, "0.00" alone is equivalent to "0.00;-0.00".
  157. * If there is an explicit negative subpattern, it serves only to specify the
  158. * negative prefix and suffix; the number of digits, minimal digits, and other
  159. * characteristics are all the same as the positive pattern. That means that
  160. * "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)".
  161. *
  162. * <p>If the maximum number of fraction digits is lower than the actual number
  163. * of fraction digits, then <code>format()</code> will round the result to the
  164. * maximum number of fraction digits. The rounding is performed according to
  165. * the IEEE 754 default rounding mode known as <em>half even</em>: Numbers are
  166. * rounded toward the nearest truncated value, unless both truncated values are
  167. * equidistant, in which case the value ending in an even digit is chosen.
  168. *
  169. * <p>For example, formatting the number 1.2499 with a maximum of two fraction
  170. * digits gives two possible values, 1.24 and 1.25. The distance to 1.24 is
  171. * 0.0099 and the distance to 1.25 is 0.0001, so 1.25 is chosen. On the other
  172. * hand, when rounding 1.245 to two fraction digits, the two possible values are
  173. * again 1.24 and 1.25, but the distance to each is the same: 0.005. In this
  174. * case 1.24 is chosen because it ends in an even digit.
  175. *
  176. * <p>
  177. * The exponent character must be immediately followed by one or more
  178. * digit characters. Example: "0.###E0". The number of digit characters
  179. * after the exponent character gives the minimum exponent digit count;
  180. * there is no maximum. Negative exponents are denoted using the same
  181. * prefix and/or suffix specified for the number itself. The minimum
  182. * number of integer digits is achieved by adjusting the exponent. The
  183. * maximum number of integer digits, if any, specifies the exponent
  184. * grouping. For example, 12345 is formatted using "##0.###E0" as
  185. * "12.345E3".
  186. * <p>
  187. * Illegal patterns, such as "#.#.#" or mixing '_' and '*' in the
  188. * same pattern, will cause an <code>IllegalArgumentException</code> to be
  189. * thrown. From the message of <code>IllegalArgumentException</code>, you can
  190. * find the place in the string where the error occurred.
  191. *
  192. * <p>
  193. * The grouping separator is commonly used for thousands, but in some
  194. * countries for ten-thousands. The interval is a constant number of
  195. * digits between the grouping characters, such as 100,000,000 or 1,0000,0000.
  196. * If you supply a pattern with multiple grouping characters, the interval
  197. * between the last one and the end of the integer is the one that is
  198. * used. So "#,##,###,####" == "######,####" == "##,####,####".
  199. *
  200. * <p>
  201. * When calling DecimalFormat.parse(String, ParsePosition) and parsing
  202. * fails, a null object will be returned. The unchanged parse position
  203. * also reflects that an error has occurred during parsing. When calling
  204. * the convenient method DecimalFormat.parse(String) and parsing fails,
  205. * a ParseException will be thrown.
  206. * <p>
  207. * This class handles all Unicode characters that represent decimal digits.
  208. * This set of characters is defined in the Unicode standard.
  209. *
  210. * @see java.text.Format
  211. * @see java.text.NumberFormat
  212. * @see java.text.ChoiceFormat
  213. * @version 1.51 11/29/01
  214. * @author Mark Davis
  215. * @author Alan Liu
  216. */
  217. /*
  218. * Requested Features
  219. * Symbol Meaning
  220. * $ currency symbol as decimal point
  221. * \u0085 escapes text
  222. * \u2030 divide by 1000 and show as per/mil
  223. */
  224. public class DecimalFormat extends NumberFormat {
  225. /**
  226. * Create a DecimalFormat using the default pattern and symbols
  227. * for the default locale. This is a convenient way to obtain a
  228. * DecimalFormat when internationalization is not the main concern.
  229. * <p>
  230. * To obtain standard formats for a given locale, use the factory methods
  231. * on NumberFormat such as getNumberInstance. These factories will
  232. * return the most appropriate sub-class of NumberFormat for a given
  233. * locale.
  234. * @see java.text.NumberFormat#getInstance
  235. * @see java.text.NumberFormat#getNumberInstance
  236. * @see java.text.NumberFormat#getCurrencyInstance
  237. * @see java.text.NumberFormat#getPercentInstance
  238. */
  239. public DecimalFormat() {
  240. Locale def = Locale.getDefault();
  241. /* try to get the pattern from the cache */
  242. String pattern = (String) cachedLocaleData.get(def);
  243. if (pattern == null) { /* cache miss */
  244. // Get the pattern for the default locale.
  245. ResourceBundle rb = ResourceBundle.getBundle
  246. ("java.text.resources.LocaleElements", def);
  247. String[] all = rb.getStringArray("NumberPatterns");
  248. pattern = all[0];
  249. /* update cache */
  250. cachedLocaleData.put(def, pattern);
  251. }
  252. /* Always applyPattern after the symbols are set */
  253. this.symbols = new DecimalFormatSymbols( def );
  254. applyPattern( pattern, false );
  255. }
  256. /**
  257. * Create a DecimalFormat from the given pattern and the symbols
  258. * for the default locale. This is a convenient way to obtain a
  259. * DecimalFormat when internationalization is not the main concern.
  260. * <p>
  261. * To obtain standard formats for a given locale, use the factory methods
  262. * on NumberFormat such as getNumberInstance. These factories will
  263. * return the most appropriate sub-class of NumberFormat for a given
  264. * locale.
  265. * @param pattern A non-localized pattern string.
  266. * @exception IllegalArgumentException if the given pattern is invalid.
  267. * @see java.text.NumberFormat#getInstance
  268. * @see java.text.NumberFormat#getNumberInstance
  269. * @see java.text.NumberFormat#getCurrencyInstance
  270. * @see java.text.NumberFormat#getPercentInstance
  271. */
  272. public DecimalFormat(String pattern) {
  273. // Always applyPattern after the symbols are set
  274. this.symbols = new DecimalFormatSymbols( Locale.getDefault() );
  275. applyPattern( pattern, false );
  276. }
  277. /**
  278. * Create a DecimalFormat from the given pattern and symbols.
  279. * Use this constructor when you need to completely customize the
  280. * behavior of the format.
  281. * <p>
  282. * To obtain standard formats for a given
  283. * locale, use the factory methods on NumberFormat such as
  284. * getInstance or getCurrencyInstance. If you need only minor adjustments
  285. * to a standard format, you can modify the format returned by
  286. * a NumberFormat factory method.
  287. * @param pattern a non-localized pattern string
  288. * @param symbols the set of symbols to be used
  289. * @exception IllegalArgumentException if the given pattern is invalid
  290. * @see java.text.NumberFormat#getInstance
  291. * @see java.text.NumberFormat#getNumberInstance
  292. * @see java.text.NumberFormat#getCurrencyInstance
  293. * @see java.text.NumberFormat#getPercentInstance
  294. * @see java.text.DecimalFormatSymbols
  295. */
  296. public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
  297. // Always applyPattern after the symbols are set
  298. this.symbols = (DecimalFormatSymbols)symbols.clone();
  299. applyPattern( pattern, false );
  300. }
  301. // Overrides
  302. public StringBuffer format(double number, StringBuffer result,
  303. FieldPosition fieldPosition)
  304. {
  305. fieldPosition.setBeginIndex(0);
  306. fieldPosition.setEndIndex(0);
  307. if (Double.isNaN(number))
  308. {
  309. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  310. fieldPosition.setBeginIndex(result.length());
  311. result.append(symbols.getNaN());
  312. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  313. fieldPosition.setEndIndex(result.length());
  314. return result;
  315. }
  316. /* Detecting whether a double is negative is easy with the exception of
  317. * the value -0.0. This is a double which has a zero mantissa (and
  318. * exponent), but a negative sign bit. It is semantically distinct from
  319. * a zero with a positive sign bit, and this distinction is important
  320. * to certain kinds of computations. However, it's a little tricky to
  321. * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
  322. * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
  323. * -Infinity. Proper detection of -0.0 is needed to deal with the
  324. * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
  325. */
  326. boolean isNegative = (number < 0.0) || (number == 0.0 && 1/number < 0.0);
  327. if (isNegative) number = -number;
  328. // Do this BEFORE checking to see if value is infinite!
  329. if (multiplier != 1) number *= multiplier;
  330. if (Double.isInfinite(number))
  331. {
  332. result.append(isNegative ? negativePrefix : positivePrefix);
  333. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  334. fieldPosition.setBeginIndex(result.length());
  335. result.append(symbols.getInfinity());
  336. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  337. fieldPosition.setEndIndex(result.length());
  338. result.append(isNegative ? negativeSuffix : positiveSuffix);
  339. return result;
  340. }
  341. // At this point we are guaranteed a nonnegative finite
  342. // number.
  343. synchronized(digitList) {
  344. digitList.set(number, useExponentialNotation ?
  345. getMaximumIntegerDigits() + getMaximumFractionDigits() :
  346. getMaximumFractionDigits(),
  347. !useExponentialNotation);
  348. return subformat(result, fieldPosition, isNegative, false);
  349. }
  350. }
  351. public StringBuffer format(long number, StringBuffer result,
  352. FieldPosition fieldPosition)
  353. {
  354. fieldPosition.setBeginIndex(0);
  355. fieldPosition.setEndIndex(0);
  356. boolean isNegative = (number < 0);
  357. if (isNegative) number = -number;
  358. // In general, long values always represent real finite numbers, so
  359. // we don't have to check for +/- Infinity or NaN. However, there
  360. // is one case we have to be careful of: The multiplier can push
  361. // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
  362. // check for this before multiplying, and if it happens we use doubles
  363. // instead, trading off accuracy for range.
  364. if (multiplier != 1 && multiplier != 0)
  365. {
  366. boolean useDouble = false;
  367. if (number < 0) // This can only happen if number == Long.MIN_VALUE
  368. {
  369. long cutoff = Long.MIN_VALUE / multiplier;
  370. useDouble = (number < cutoff);
  371. }
  372. else
  373. {
  374. long cutoff = Long.MAX_VALUE / multiplier;
  375. useDouble = (number > cutoff);
  376. }
  377. if (useDouble)
  378. {
  379. double dnumber = (double)(isNegative ? -number : number);
  380. return format(dnumber, result, fieldPosition);
  381. }
  382. }
  383. number *= multiplier;
  384. synchronized(digitList) {
  385. digitList.set(number, useExponentialNotation ?
  386. getMaximumIntegerDigits() + getMaximumFractionDigits() : 0);
  387. return subformat(result, fieldPosition, isNegative, true);
  388. }
  389. }
  390. /**
  391. * Complete the formatting of a finite number. On entry, the digitList must
  392. * be filled in with the correct digits.
  393. */
  394. private StringBuffer subformat(StringBuffer result, FieldPosition fieldPosition,
  395. boolean isNegative, boolean isInteger)
  396. {
  397. // NOTE: This isn't required anymore because DigitList takes care of this.
  398. //
  399. // // The negative of the exponent represents the number of leading
  400. // // zeros between the decimal and the first non-zero digit, for
  401. // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
  402. // // is more than the maximum fraction digits, then we have an underflow
  403. // // for the printed representation. We recognize this here and set
  404. // // the DigitList representation to zero in this situation.
  405. //
  406. // if (-digitList.decimalAt >= getMaximumFractionDigits())
  407. // {
  408. // digitList.count = 0;
  409. // }
  410. char zero = symbols.getZeroDigit();
  411. int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
  412. char grouping = symbols.getGroupingSeparator();
  413. char decimal = isCurrencyFormat ?
  414. symbols.getMonetaryDecimalSeparator() :
  415. symbols.getDecimalSeparator();
  416. /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
  417. * format as zero. This allows sensible computations and preserves
  418. * relations such as signum(1/x) = signum(x), where x is +Infinity or
  419. * -Infinity. Prior to this fix, we always formatted zero values as if
  420. * they were positive. Liu 7/6/98.
  421. */
  422. if (digitList.isZero())
  423. {
  424. digitList.decimalAt = 0; // Normalize
  425. }
  426. result.append(isNegative ? negativePrefix : positivePrefix);
  427. if (useExponentialNotation)
  428. {
  429. // Record field information for caller.
  430. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  431. {
  432. fieldPosition.setBeginIndex(result.length());
  433. fieldPosition.setEndIndex(-1);
  434. }
  435. else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  436. {
  437. fieldPosition.setBeginIndex(-1);
  438. }
  439. // Minimum integer digits are handled in exponential format by
  440. // adjusting the exponent. For example, 0.01234 with 3 minimum
  441. // integer digits is "123.4E-4".
  442. // Maximum integer digits are interpreted as indicating the
  443. // repeating range. This is useful for engineering notation, in
  444. // which the exponent is restricted to a multiple of 3. For
  445. // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
  446. // If maximum integer digits are defined and are larger than
  447. // minimum integer digits, then minimum integer digits are
  448. // ignored.
  449. int exponent = digitList.decimalAt;
  450. int repeat = getMaximumIntegerDigits();
  451. if (repeat > 1 &&
  452. repeat != getMinimumIntegerDigits())
  453. {
  454. // A repeating range is defined; adjust to it as follows.
  455. // If repeat == 3, we have 5,4,3=>3; 2,1,0=>0; -1,-2,-3=>-3;
  456. // -4,-5-,6=>-6, etc. Also, the exponent we have here is
  457. // off by one from what we expect; that is, it is for the format
  458. // 0.MMMMMx10^n. So we subtract another 1 to get it in range.
  459. exponent -= (exponent < 0) ? repeat : 1;
  460. exponent = (exponent / repeat) * repeat;
  461. }
  462. else
  463. {
  464. // No repeating range is defined; use minimum integer digits.
  465. exponent -= getMinimumIntegerDigits();
  466. }
  467. // We now output a minimum number of digits, and more if there
  468. // are more digits, up to the maximum number of digits. We
  469. // place the decimal point after the "integer" digits, which
  470. // are the first (decimalAt - exponent) digits.
  471. int minimumDigits = getMinimumIntegerDigits()
  472. + getMinimumFractionDigits();
  473. // The number of integer digits is handled specially if the number
  474. // is zero, since then there may be no digits.
  475. int integerDigits = digitList.isZero() ? getMinimumIntegerDigits() :
  476. digitList.decimalAt - exponent;
  477. int totalDigits = digitList.count;
  478. if (minimumDigits > totalDigits) totalDigits = minimumDigits;
  479. for (int i=0; i<totalDigits; ++i)
  480. {
  481. if (i == integerDigits)
  482. {
  483. // Record field information for caller.
  484. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  485. fieldPosition.setEndIndex(result.length());
  486. result.append(decimal);
  487. // Record field information for caller.
  488. if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  489. fieldPosition.setBeginIndex(result.length());
  490. }
  491. result.append((i < digitList.count) ?
  492. (char)(digitList.digits[i] + zeroDelta) :
  493. zero);
  494. }
  495. // Record field information
  496. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  497. {
  498. if (fieldPosition.getEndIndex() < 0)
  499. fieldPosition.setEndIndex(result.length());
  500. }
  501. else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  502. {
  503. if (fieldPosition.getBeginIndex() < 0)
  504. fieldPosition.setBeginIndex(result.length());
  505. fieldPosition.setEndIndex(result.length());
  506. }
  507. // The exponent is output using the pattern-specified minimum
  508. // exponent digits. There is no maximum limit to the exponent
  509. // digits, since truncating the exponent would result in an
  510. // unacceptable inaccuracy.
  511. result.append(symbols.getExponentialSymbol());
  512. // For zero values, we force the exponent to zero. We
  513. // must do this here, and not earlier, because the value
  514. // is used to determine integer digit count above.
  515. if (digitList.isZero()) exponent = 0;
  516. boolean negativeExponent = exponent < 0;
  517. if (negativeExponent) exponent = -exponent;
  518. result.append(negativeExponent ? negativePrefix : positivePrefix);
  519. digitList.set(exponent);
  520. for (int i=digitList.decimalAt; i<minExponentDigits; ++i) result.append(zero);
  521. for (int i=0; i<digitList.decimalAt; ++i)
  522. {
  523. result.append((i < digitList.count) ?
  524. (char)(digitList.digits[i] + zeroDelta) : zero);
  525. }
  526. result.append(negativeExponent ? negativeSuffix : positiveSuffix);
  527. }
  528. else
  529. {
  530. // Record field information for caller.
  531. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  532. fieldPosition.setBeginIndex(result.length());
  533. // Output the integer portion. Here 'count' is the total
  534. // number of integer digits we will display, including both
  535. // leading zeros required to satisfy getMinimumIntegerDigits,
  536. // and actual digits present in the number.
  537. int count = getMinimumIntegerDigits();
  538. int digitIndex = 0; // Index into digitList.fDigits[]
  539. if (digitList.decimalAt > 0 && count < digitList.decimalAt)
  540. count = digitList.decimalAt;
  541. // Handle the case where getMaximumIntegerDigits() is smaller
  542. // than the real number of integer digits. If this is so, we
  543. // output the least significant max integer digits. For example,
  544. // the value 1997 printed with 2 max integer digits is just "97".
  545. if (count > getMaximumIntegerDigits())
  546. {
  547. count = getMaximumIntegerDigits();
  548. digitIndex = digitList.decimalAt - count;
  549. }
  550. int sizeBeforeIntegerPart = result.length();
  551. for (int i=count-1; i>=0; --i)
  552. {
  553. if (i < digitList.decimalAt && digitIndex < digitList.count)
  554. {
  555. // Output a real digit
  556. result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  557. }
  558. else
  559. {
  560. // Output a leading zero
  561. result.append(zero);
  562. }
  563. // Output grouping separator if necessary. Don't output a
  564. // grouping separator if i==0 though; that's at the end of
  565. // the integer part.
  566. if (isGroupingUsed() && i>0 && (groupingSize != 0) && (i % groupingSize == 0))
  567. {
  568. result.append(grouping);
  569. }
  570. }
  571. // Record field information for caller.
  572. if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  573. fieldPosition.setEndIndex(result.length());
  574. // Determine whether or not there are any printable fractional
  575. // digits. If we've used up the digits we know there aren't.
  576. boolean fractionPresent = (getMinimumFractionDigits() > 0) ||
  577. (!isInteger && digitIndex < digitList.count);
  578. // If there is no fraction present, and we haven't printed any
  579. // integer digits, then print a zero. Otherwise we won't print
  580. // _any_ digits, and we won't be able to parse this string.
  581. if (!fractionPresent && result.length() == sizeBeforeIntegerPart)
  582. result.append(zero);
  583. // Output the decimal separator if we always do so.
  584. if (decimalSeparatorAlwaysShown || fractionPresent)
  585. result.append(decimal);
  586. // Record field information for caller.
  587. if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  588. fieldPosition.setBeginIndex(result.length());
  589. for (int i=0; i < getMaximumFractionDigits(); ++i)
  590. {
  591. // Here is where we escape from the loop. We escape if we've output
  592. // the maximum fraction digits (specified in the for expression above).
  593. // We also stop when we've output the minimum digits and either:
  594. // we have an integer, so there is no fractional stuff to display,
  595. // or we're out of significant digits.
  596. if (i >= getMinimumFractionDigits() &&
  597. (isInteger || digitIndex >= digitList.count))
  598. break;
  599. // Output leading fractional zeros. These are zeros that come after
  600. // the decimal but before any significant digits. These are only
  601. // output if abs(number being formatted) < 1.0.
  602. if (-1-i > (digitList.decimalAt-1))
  603. {
  604. result.append(zero);
  605. continue;
  606. }
  607. // Output a digit, if we have any precision left, or a
  608. // zero if we don't. We don't want to output noise digits.
  609. if (!isInteger && digitIndex < digitList.count)
  610. {
  611. result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  612. }
  613. else
  614. {
  615. result.append(zero);
  616. }
  617. }
  618. // Record field information for caller.
  619. if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  620. fieldPosition.setEndIndex(result.length());
  621. }
  622. result.append(isNegative ? negativeSuffix : positiveSuffix);
  623. return result;
  624. }
  625. public Number parse(String text, ParsePosition parsePosition)
  626. {
  627. // special case NaN
  628. if (text.regionMatches(parsePosition.index, symbols.getNaN(),
  629. 0, symbols.getNaN().length())) {
  630. parsePosition.index = parsePosition.index + symbols.getNaN().length();
  631. return new Double(Double.NaN);
  632. }
  633. boolean[] status = new boolean[STATUS_LENGTH];
  634. if (!subparse(text, parsePosition, digitList, false, status))
  635. return null;
  636. double doubleResult = 0.0;
  637. long longResult = 0;
  638. boolean gotDouble = true;
  639. // Finally, have DigitList parse the digits into a value.
  640. if (status[STATUS_INFINITE])
  641. {
  642. doubleResult = Double.POSITIVE_INFINITY;
  643. }
  644. else if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly()))
  645. {
  646. gotDouble = false;
  647. longResult = digitList.getLong();
  648. }
  649. else doubleResult = digitList.getDouble();
  650. // Divide by multiplier. We have to be careful here not to do unneeded
  651. // conversions between double and long.
  652. if (multiplier != 1)
  653. {
  654. if (gotDouble)
  655. doubleResult /= multiplier;
  656. else {
  657. // Avoid converting to double if we can
  658. if (longResult % multiplier == 0) {
  659. longResult /= multiplier;
  660. } else {
  661. doubleResult = ((double)longResult) / multiplier;
  662. if (doubleResult < 0) doubleResult = -doubleResult;
  663. gotDouble = true;
  664. }
  665. }
  666. }
  667. if (!status[STATUS_POSITIVE])
  668. {
  669. doubleResult = -doubleResult;
  670. longResult = -longResult;
  671. }
  672. // At this point, if we divided the result by the multiplier, the result may
  673. // fit into a long. We check for this case and return a long if possible.
  674. // We must do this AFTER applying the negative (if appropriate) in order to
  675. // handle the case of LONG_MIN; otherwise, if we do this with a positive value
  676. // -LONG_MIN, the double is > 0, but the long is < 0. This is a C++-specific
  677. // situation. We also must retain a double in the case of -0.0, which will
  678. // compare as == to a long 0 cast to a double (bug 4162852).
  679. if (multiplier != 1 && gotDouble)
  680. {
  681. longResult = (long)doubleResult;
  682. gotDouble = (doubleResult != (double)longResult)
  683. || (doubleResult == 0.0 && !status[STATUS_POSITIVE] && !isParseIntegerOnly());
  684. }
  685. return gotDouble ? (Number)new Double(doubleResult) : (Number)new Long(longResult);
  686. }
  687. private static final int STATUS_INFINITE = 0;
  688. private static final int STATUS_POSITIVE = 1;
  689. private static final int STATUS_LENGTH = 2;
  690. /**
  691. * Parse the given text into a number. The text is parsed beginning at
  692. * parsePosition, until an unparseable character is seen.
  693. * @param text The string to parse.
  694. * @param parsePosition The position at which to being parsing. Upon
  695. * return, the first unparseable character.
  696. * @param digits The DigitList to set to the parsed value.
  697. * @param isExponent If true, parse an exponent. This means no
  698. * infinite values and integer only.
  699. * @param status Upon return contains boolean status flags indicating
  700. * whether the value was infinite and whether it was positive.
  701. */
  702. private final boolean subparse(String text, ParsePosition parsePosition,
  703. DigitList digits, boolean isExponent,
  704. boolean status[])
  705. {
  706. int position = parsePosition.index;
  707. int oldStart = parsePosition.index;
  708. int backup;
  709. // check for positivePrefix; take longest
  710. boolean gotPositive = text.regionMatches(position,positivePrefix,0,
  711. positivePrefix.length());
  712. boolean gotNegative = text.regionMatches(position,negativePrefix,0,
  713. negativePrefix.length());
  714. if (gotPositive && gotNegative) {
  715. if (positivePrefix.length() > negativePrefix.length())
  716. gotNegative = false;
  717. else if (positivePrefix.length() < negativePrefix.length())
  718. gotPositive = false;
  719. }
  720. if (gotPositive) {
  721. position += positivePrefix.length();
  722. } else if (gotNegative) {
  723. position += negativePrefix.length();
  724. } else {
  725. parsePosition.errorIndex = position;
  726. return false;
  727. }
  728. // process digits or Inf, find decimal position
  729. status[STATUS_INFINITE] = false;
  730. if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
  731. symbols.getInfinity().length()))
  732. {
  733. position += symbols.getInfinity().length();
  734. status[STATUS_INFINITE] = true;
  735. } else {
  736. // We now have a string of digits, possibly with grouping symbols,
  737. // and decimal points. We want to process these into a DigitList.
  738. // We don't want to put a bunch of leading zeros into the DigitList
  739. // though, so we keep track of the location of the decimal point,
  740. // put only significant digits into the DigitList, and adjust the
  741. // exponent as needed.
  742. digits.decimalAt = digits.count = 0;
  743. char zero = symbols.getZeroDigit();
  744. char decimal = isCurrencyFormat ?
  745. symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator();
  746. char grouping = symbols.getGroupingSeparator();
  747. char exponentChar = symbols.getExponentialSymbol();
  748. boolean sawDecimal = false;
  749. boolean sawExponent = false;
  750. boolean sawDigit = false;
  751. int exponent = 0; // Set to the exponent value, if any
  752. // We have to track digitCount ourselves, because digits.count will
  753. // pin when the maximum allowable digits is reached.
  754. int digitCount = 0;
  755. backup = -1;
  756. for (; position < text.length(); ++position)
  757. {
  758. char ch = text.charAt(position);
  759. /* We recognize all digit ranges, not only the Latin digit range
  760. * '0'..'9'. We do so by using the Character.digit() method,
  761. * which converts a valid Unicode digit to the range 0..9.
  762. *
  763. * The character 'ch' may be a digit. If so, place its value
  764. * from 0 to 9 in 'digit'. First try using the locale digit,
  765. * which may or MAY NOT be a standard Unicode digit range. If
  766. * this fails, try using the standard Unicode digit ranges by
  767. * calling Character.digit(). If this also fails, digit will
  768. * have a value outside the range 0..9.
  769. */
  770. int digit = ch - zero;
  771. if (digit < 0 || digit > 9) digit = Character.digit(ch, 10);
  772. if (digit == 0)
  773. {
  774. // Cancel out backup setting (see grouping handler below)
  775. backup = -1; // Do this BEFORE continue statement below!!!
  776. sawDigit = true;
  777. // Handle leading zeros
  778. if (digits.count == 0)
  779. {
  780. // Ignore leading zeros in integer part of number.
  781. if (!sawDecimal) continue;
  782. // If we have seen the decimal, but no significant digits yet,
  783. // then we account for leading zeros by decrementing the
  784. // digits.decimalAt into negative values.
  785. --digits.decimalAt;
  786. }
  787. else
  788. {
  789. ++digitCount;
  790. digits.append((char)(digit + '0'));
  791. }
  792. }
  793. else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above
  794. {
  795. sawDigit = true;
  796. ++digitCount;
  797. digits.append((char)(digit + '0'));
  798. // Cancel out backup setting (see grouping handler below)
  799. backup = -1;
  800. }
  801. else if (!isExponent && ch == decimal)
  802. {
  803. // If we're only parsing integers, or if we ALREADY saw the
  804. // decimal, then don't parse this one.
  805. if (isParseIntegerOnly() || sawDecimal) break;
  806. digits.decimalAt = digitCount; // Not digits.count!
  807. sawDecimal = true;
  808. }
  809. else if (!isExponent && ch == grouping && isGroupingUsed())
  810. {
  811. if (sawDecimal) {
  812. break;
  813. }
  814. // Ignore grouping characters, if we are using them, but require
  815. // that they be followed by a digit. Otherwise we backup and
  816. // reprocess them.
  817. backup = position;
  818. }
  819. else if (!isExponent && ch == exponentChar && !sawExponent)
  820. {
  821. // Process the exponent by recursively calling this method.
  822. ParsePosition pos = new ParsePosition(position + 1);
  823. boolean[] stat = new boolean[STATUS_LENGTH];
  824. DigitList exponentDigits = new DigitList();
  825. if (subparse(text, pos, exponentDigits, true, stat) &&
  826. exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true))
  827. {
  828. position = pos.index; // Advance past the exponent
  829. exponent = (int)exponentDigits.getLong();
  830. if (!stat[STATUS_POSITIVE]) exponent = -exponent;
  831. sawExponent = true;
  832. }
  833. break; // Whether we fail or succeed, we exit this loop
  834. }
  835. else break;
  836. }
  837. if (backup != -1) position = backup;
  838. // If there was no decimal point we have an integer
  839. if (!sawDecimal) digits.decimalAt = digitCount; // Not digits.count!
  840. // Adjust for exponent, if any
  841. digits.decimalAt += exponent;
  842. // If none of the text string was recognized. For example, parse
  843. // "x" with pattern "#0.00" (return index and error index both 0)
  844. // parse "$" with pattern "$#0.00". (return index 0 and error index
  845. // 1).
  846. if (!sawDigit && digitCount == 0) {
  847. parsePosition.index = oldStart;
  848. parsePosition.errorIndex = oldStart;
  849. return false;
  850. }
  851. }
  852. // check for positiveSuffix
  853. if (gotPositive)
  854. gotPositive = text.regionMatches(position,positiveSuffix,0,
  855. positiveSuffix.length());
  856. if (gotNegative)
  857. gotNegative = text.regionMatches(position,negativeSuffix,0,
  858. negativeSuffix.length());
  859. // if both match, take longest
  860. if (gotPositive && gotNegative) {
  861. if (positiveSuffix.length() > negativeSuffix.length())
  862. gotNegative = false;
  863. else if (positiveSuffix.length() < negativeSuffix.length())
  864. gotPositive = false;
  865. }
  866. // fail if neither or both
  867. if (gotPositive == gotNegative) {
  868. parsePosition.errorIndex = position;
  869. return false;
  870. }
  871. parsePosition.index = position +
  872. (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
  873. status[STATUS_POSITIVE] = gotPositive;
  874. if (parsePosition.index == oldStart) {
  875. parsePosition.errorIndex = position;
  876. return false;
  877. }
  878. return true;
  879. }
  880. /**
  881. * Returns the decimal format symbols, which is generally not changed
  882. * by the programmer or user.
  883. * @return desired DecimalFormatSymbols
  884. * @see java.text.DecimalFormatSymbols
  885. */
  886. public DecimalFormatSymbols getDecimalFormatSymbols() {
  887. try {
  888. // don't allow multiple references
  889. return (DecimalFormatSymbols) symbols.clone();
  890. } catch (Exception foo) {
  891. return null; // should never happen
  892. }
  893. }
  894. /**
  895. * Sets the decimal format symbols, which is generally not changed
  896. * by the programmer or user.
  897. * @param newSymbols desired DecimalFormatSymbols
  898. * @see java.text.DecimalFormatSymbols
  899. */
  900. public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
  901. try {
  902. // don't allow multiple references
  903. symbols = (DecimalFormatSymbols) newSymbols.clone();
  904. } catch (Exception foo) {
  905. // should never happen
  906. }
  907. }
  908. /**
  909. * Get the positive prefix.
  910. * <P>Examples: +123, $123, sFr123
  911. */
  912. public String getPositivePrefix () {
  913. return positivePrefix;
  914. }
  915. /**
  916. * Set the positive prefix.
  917. * <P>Examples: +123, $123, sFr123
  918. */
  919. public void setPositivePrefix (String newValue) {
  920. positivePrefix = newValue;
  921. }
  922. /**
  923. * Get the negative prefix.
  924. * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  925. */
  926. public String getNegativePrefix () {
  927. return negativePrefix;
  928. }
  929. /**
  930. * Set the negative prefix.
  931. * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  932. */
  933. public void setNegativePrefix (String newValue) {
  934. negativePrefix = newValue;
  935. }
  936. /**
  937. * Get the positive suffix.
  938. * <P>Example: 123%
  939. */
  940. public String getPositiveSuffix () {
  941. return positiveSuffix;
  942. }
  943. /**
  944. * Set the positive suffix.
  945. * <P>Example: 123%
  946. */
  947. public void setPositiveSuffix (String newValue) {
  948. positiveSuffix = newValue;
  949. }
  950. /**
  951. * Get the negative suffix.
  952. * <P>Examples: -123%, ($123) (with positive suffixes)
  953. */
  954. public String getNegativeSuffix () {
  955. return negativeSuffix;
  956. }
  957. /**
  958. * Set the positive suffix.
  959. * <P>Examples: 123%
  960. */
  961. public void setNegativeSuffix (String newValue) {
  962. negativeSuffix = newValue;
  963. }
  964. /**
  965. * Get the multiplier for use in percent, permill, etc.
  966. * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  967. * (For Arabic, use arabic percent symbol).
  968. * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  969. * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  970. */
  971. public int getMultiplier () {
  972. return multiplier;
  973. }
  974. /**
  975. * Set the multiplier for use in percent, permill, etc.
  976. * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  977. * (For Arabic, use arabic percent symbol).
  978. * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  979. * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  980. */
  981. public void setMultiplier (int newValue) {
  982. multiplier = newValue;
  983. }
  984. /**
  985. * Return the grouping size. Grouping size is the number of digits between
  986. * grouping separators in the integer portion of a number. For example,
  987. * in the number "123,456.78", the grouping size is 3.
  988. * @see #setGroupingSize
  989. * @see java.text.NumberFormat#isGroupingUsed
  990. * @see java.text.DecimalFormatSymbols#getGroupingSeparator
  991. */
  992. public int getGroupingSize () {
  993. return groupingSize;
  994. }
  995. /**
  996. * Set the grouping size. Grouping size is the number of digits between
  997. * grouping separators in the integer portion of a number. For example,
  998. * in the number "123,456.78", the grouping size is 3.
  999. * @see #getGroupingSize
  1000. * @see java.text.NumberFormat#setGroupingUsed
  1001. * @see java.text.DecimalFormatSymbols#setGroupingSeparator
  1002. */
  1003. public void setGroupingSize (int newValue) {
  1004. groupingSize = (byte)newValue;
  1005. }
  1006. /**
  1007. * Allows you to get the behavior of the decimal separator with integers.
  1008. * (The decimal separator will always appear with decimals.)
  1009. * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1010. */
  1011. public boolean isDecimalSeparatorAlwaysShown() {
  1012. return decimalSeparatorAlwaysShown;
  1013. }
  1014. /**
  1015. * Allows you to set the behavior of the decimal separator with integers.
  1016. * (The decimal separator will always appear with decimals.)
  1017. * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1018. */
  1019. public void setDecimalSeparatorAlwaysShown(boolean newValue) {
  1020. decimalSeparatorAlwaysShown = newValue;
  1021. }
  1022. /**
  1023. * Standard override; no change in semantics.
  1024. */
  1025. public Object clone() {
  1026. try {
  1027. DecimalFormat other = (DecimalFormat) super.clone();
  1028. other.symbols = (DecimalFormatSymbols) symbols.clone();
  1029. return other;
  1030. } catch (Exception e) {
  1031. throw new InternalError();
  1032. }
  1033. }
  1034. /**
  1035. * Overrides equals
  1036. */
  1037. public boolean equals(Object obj)
  1038. {
  1039. if (obj == null) return false;
  1040. if (!super.equals(obj)) return false; // super does class check
  1041. DecimalFormat other = (DecimalFormat) obj;
  1042. return (positivePrefix.equals(other.positivePrefix)
  1043. && positiveSuffix.equals(other.positiveSuffix)
  1044. && negativePrefix.equals(other.negativePrefix)
  1045. && negativeSuffix.equals(other.negativeSuffix)
  1046. && multiplier == other.multiplier
  1047. && groupingSize == other.groupingSize
  1048. && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
  1049. && useExponentialNotation == other.useExponentialNotation
  1050. && (!useExponentialNotation ||
  1051. minExponentDigits == other.minExponentDigits)
  1052. && symbols.equals(other.symbols));
  1053. }
  1054. /**
  1055. * Overrides hashCode
  1056. */
  1057. public int hashCode() {
  1058. return super.hashCode() * 37 + positivePrefix.hashCode();
  1059. // just enough fields for a reasonable distribution
  1060. }
  1061. /**
  1062. * Synthesizes a pattern string that represents the current state
  1063. * of this Format object.
  1064. * @see #applyPattern
  1065. */
  1066. public String toPattern() {
  1067. return toPattern( false );
  1068. }
  1069. /**
  1070. * Synthesizes a localized pattern string that represents the current
  1071. * state of this Format object.
  1072. * @see #applyPattern
  1073. */
  1074. public String toLocalizedPattern() {
  1075. return toPattern( true );
  1076. }
  1077. /**
  1078. * Append an affix to the given StringBuffer, using quotes if
  1079. * there are special characters. Single quotes themselves must be
  1080. * escaped in either case.
  1081. */
  1082. private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
  1083. boolean needQuote;
  1084. if (localized) {
  1085. needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
  1086. || affix.indexOf(symbols.getGroupingSeparator()) >= 0
  1087. || affix.indexOf(symbols.getDecimalSeparator()) >= 0
  1088. || affix.indexOf(symbols.getPercent()) >= 0
  1089. || affix.indexOf(symbols.getPerMill()) >= 0
  1090. || affix.indexOf(symbols.getDigit()) >= 0
  1091. || affix.indexOf(symbols.getPatternSeparator()) >= 0
  1092. || affix.indexOf(symbols.getExponentialSymbol()) >= 0;
  1093. }
  1094. else {
  1095. needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
  1096. || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
  1097. || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
  1098. || affix.indexOf(PATTERN_PERCENT) >= 0
  1099. || affix.indexOf(PATTERN_PER_MILLE) >= 0
  1100. || affix.indexOf(PATTERN_DIGIT) >= 0
  1101. || affix.indexOf(PATTERN_SEPARATOR) >= 0
  1102. || affix.indexOf(PATTERN_EXPONENT) >= 0;
  1103. }
  1104. if (needQuote) buffer.append('\'');
  1105. if (affix.indexOf('\'') < 0) buffer.append(affix);
  1106. else {
  1107. for (int j=0; j<affix.length(); ++j) {
  1108. char c = affix.charAt(j);
  1109. buffer.append(c);
  1110. if (c == '\'') buffer.append(c);
  1111. }
  1112. }
  1113. if (needQuote) buffer.append('\'');
  1114. }
  1115. /**
  1116. * Does the real work of generating a pattern. */
  1117. private String toPattern(boolean localized) {
  1118. StringBuffer result = new StringBuffer();
  1119. for (int j = 1; j >= 0; --j) {
  1120. if (j == 1)
  1121. appendAffix(result, positivePrefix, localized);
  1122. else appendAffix(result, negativePrefix, localized);
  1123. int i;
  1124. if (useExponentialNotation)
  1125. {
  1126. for (i = getMaximumIntegerDigits(); i > 0; --i)
  1127. {
  1128. if (i == groupingSize)
  1129. result.append(localized ? symbols.getGroupingSeparator() :
  1130. PATTERN_GROUPING_SEPARATOR);
  1131. if (i <= getMinimumIntegerDigits())
  1132. result.append(localized ? symbols.getZeroDigit() :
  1133. PATTERN_ZERO_DIGIT);
  1134. else
  1135. result.append(localized ? symbols.getDigit() :
  1136. PATTERN_DIGIT);
  1137. }
  1138. }
  1139. else
  1140. {
  1141. int tempMax = Math.max(groupingSize, getMinimumIntegerDigits())+1;
  1142. for (i = tempMax; i > 0; --i) {
  1143. if (i == groupingSize)
  1144. result.append(localized ? symbols.getGroupingSeparator() :
  1145. PATTERN_GROUPING_SEPARATOR);
  1146. if (i <= getMinimumIntegerDigits()) {
  1147. result.append(localized ? symbols.getZeroDigit() :
  1148. PATTERN_ZERO_DIGIT);
  1149. } else {
  1150. result.append(localized ? symbols.getDigit() :
  1151. PATTERN_DIGIT);
  1152. }
  1153. }
  1154. }
  1155. if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
  1156. result.append(localized ? symbols.getDecimalSeparator() :
  1157. PATTERN_DECIMAL_SEPARATOR);
  1158. for (i = 0; i < getMaximumFractionDigits(); ++i) {
  1159. if (i < getMinimumFractionDigits()) {
  1160. result.append(localized ? symbols.getZeroDigit() :
  1161. PATTERN_ZERO_DIGIT);
  1162. } else {
  1163. result.append(localized ? symbols.getDigit() :
  1164. PATTERN_DIGIT);
  1165. }
  1166. }
  1167. if (useExponentialNotation)
  1168. {
  1169. result.append(localized ? symbols.getExponentialSymbol() :
  1170. PATTERN_EXPONENT);
  1171. for (i=0; i<minExponentDigits; ++i)
  1172. result.append(localized ? symbols.getZeroDigit() :
  1173. PATTERN_ZERO_DIGIT);
  1174. }
  1175. if (j == 1) {
  1176. appendAffix(result, positiveSuffix, localized);
  1177. if (negativeSuffix.equals(positiveSuffix)) {
  1178. if (negativePrefix.equals(symbols.getMinusSign() + positivePrefix))
  1179. break;
  1180. }
  1181. result.append(localized ? symbols.getPatternSeparator() :
  1182. PATTERN_SEPARATOR);
  1183. } else appendAffix(result, negativeSuffix, localized);
  1184. }
  1185. return result.toString();
  1186. }
  1187. /**
  1188. * Apply the given pattern to this Format object. A pattern is a
  1189. * short-hand specification for the various formatting properties.
  1190. * These properties can also be changed individually through the
  1191. * various setter methods.
  1192. * <p>
  1193. * There is no limit to integer digits are set
  1194. * by this routine, since that is the typical end-user desire;
  1195. * use setMaximumInteger if you want to set a real value.
  1196. * For negative numbers, use a second pattern, separated by a semicolon
  1197. * <P>Example "#,#00.0#" -> 1,234.56
  1198. * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1199. * a maximum of 2 fraction digits.
  1200. * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1201. * <p>In negative patterns, the minimum and maximum counts are ignored;
  1202. * these are presumed to be set in the positive pattern.
  1203. */
  1204. public void applyPattern( String pattern ) {
  1205. applyPattern( pattern, false );
  1206. }
  1207. /**
  1208. * Apply the given pattern to this Format object. The pattern
  1209. * is assumed to be in a localized notation. A pattern is a
  1210. * short-hand specification for the various formatting properties.
  1211. * These properties can also be changed individually through the
  1212. * various setter methods.
  1213. * <p>
  1214. * There is no limit to integer digits are set
  1215. * by this routine, since that is the typical end-user desire;
  1216. * use setMaximumInteger if you want to set a real value.
  1217. * For negative numbers, use a second pattern, separated by a semicolon
  1218. * <P>Example "#,#00.0#" -> 1,234.56
  1219. * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1220. * a maximum of 2 fraction digits.
  1221. * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1222. * <p>In negative patterns, the minimum and maximum counts are ignored;
  1223. * these are presumed to be set in the positive pattern.
  1224. */
  1225. public void applyLocalizedPattern( String pattern ) {
  1226. applyPattern( pattern, true );
  1227. }
  1228. /**
  1229. * Does the real work of applying a pattern.
  1230. */
  1231. private void applyPattern(String pattern, boolean localized)
  1232. {
  1233. char zeroDigit = PATTERN_ZERO_DIGIT;
  1234. char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
  1235. char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
  1236. char percent = PATTERN_PERCENT;
  1237. char perMill = PATTERN_PER_MILLE;
  1238. char digit = PATTERN_DIGIT;
  1239. char separator = PATTERN_SEPARATOR;
  1240. char exponent = PATTERN_EXPONENT;
  1241. if (localized) {
  1242. zeroDigit = symbols.getZeroDigit();
  1243. groupingSeparator = symbols.getGroupingSeparator();
  1244. decimalSeparator = symbols.getDecimalSeparator();
  1245. percent = symbols.getPercent();
  1246. perMill = symbols.getPerMill();
  1247. digit = symbols.getDigit();
  1248. separator = symbols.getPatternSeparator();
  1249. exponent = symbols.getExponentialSymbol();
  1250. }
  1251. boolean gotNegative = false;
  1252. decimalSeparatorAlwaysShown = false;
  1253. isCurrencyFormat = false;
  1254. useExponentialNotation = false;
  1255. // Two variables are used to record the subrange of the pattern
  1256. // occupied by phase 1. This is used during the processing of the
  1257. // second pattern (the one representing negative numbers) to ensure
  1258. // that no deviation exists in phase 1 between the two patterns.
  1259. int phaseOneStart = 0;
  1260. int phaseOneLength = 0;
  1261. /** Back-out comment : HShih
  1262. * boolean phaseTwo = false;
  1263. */
  1264. int start = 0;
  1265. for (int j = 1; j >= 0 && start < pattern.length(); --j)
  1266. {
  1267. boolean inQuote = false;
  1268. StringBuffer prefix = new StringBuffer();
  1269. StringBuffer suffix = new StringBuffer();
  1270. int decimalPos = -1;
  1271. int multiplier = 1;
  1272. int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
  1273. byte groupingCount = -1;
  1274. // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
  1275. // the section of the pattern with digits, decimal separator,
  1276. // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
  1277. // percent, permille, and currency symbols are recognized and
  1278. // translated. The separation of the characters into phases is
  1279. // strictly enforced; if phase 1 characters are to appear in the
  1280. // suffix, for example, they must be quoted.
  1281. int phase = 0;
  1282. // The affix is either the prefix or the suffix.
  1283. StringBuffer affix = prefix;
  1284. for (int pos = start; pos < pattern.length(); ++pos)
  1285. {
  1286. char ch = pattern.charAt(pos);
  1287. switch (phase)
  1288. {
  1289. case 0:
  1290. case 2:
  1291. // Process the prefix / suffix characters
  1292. if (inQuote)
  1293. {
  1294. // A quote within quotes indicates either the closing
  1295. // quote or two quotes, which is a quote literal. That is,
  1296. // we have the second quote in 'do' or 'don''t'.
  1297. if (ch == QUOTE)
  1298. {
  1299. if ((pos+1) < pattern.length() &&
  1300. pattern.charAt(pos+1) == QUOTE)
  1301. {
  1302. ++pos;
  1303. affix.append(ch); // 'don''t'
  1304. }
  1305. else
  1306. {
  1307. inQuote = false; // 'do'
  1308. }
  1309. continue;
  1310. }
  1311. }
  1312. else
  1313. {
  1314. // Process unquoted characters seen in prefix or suffix
  1315. // phase.
  1316. if (ch == digit ||
  1317. ch == zeroDigit ||
  1318. ch == groupingSeparator ||
  1319. ch == decimalSeparator)
  1320. {
  1321. // Any of these characters implicitly begins the next
  1322. // phase. If we are in phase 2, there is no next phase,
  1323. // so these characters are illegal.
  1324. /**
  1325. * 1.2 Back-out comment : HShih
  1326. * Can't throw exception here.
  1327. * if (phase == 2)
  1328. * throw new IllegalArgumentException("Unquoted special character '" +
  1329. * ch + "' in pattern \"" +
  1330. * pattern + '"');
  1331. */
  1332. phase = 1;
  1333. if (j == 1) phaseOneStart = pos;
  1334. --pos; // Reprocess this character
  1335. continue;
  1336. }
  1337. else if (ch == CURRENCY_SIGN)
  1338. {
  1339. // Use lookahead to determine if the currency sign is
  1340. // doubled or not.
  1341. boolean doubled = (pos + 1) < pattern.length() &&
  1342. pattern.charAt(pos + 1) == CURRENCY_SIGN;
  1343. affix.append(doubled ?
  1344. symbols.getInternationalCurrencySymbol() :
  1345. symbols.getCurrencySymbol());
  1346. if (doubled) ++pos; // Skip over the doubled character
  1347. isCurrencyFormat = true;
  1348. continue;
  1349. }
  1350. else if (ch == QUOTE)
  1351. {
  1352. // A quote outside quotes indicates either the opening
  1353. // quote or two quotes, which is a quote literal. That is,
  1354. // we have the first quote in 'do' or o''clock.
  1355. if (ch == QUOTE)
  1356. {
  1357. if ((pos+1) < pattern.length() &&
  1358. pattern.charAt(pos+1) == QUOTE)
  1359. {
  1360. ++pos;
  1361. affix.append(ch); // o''clock
  1362. }
  1363. else
  1364. {
  1365. inQuote = true; // 'do'
  1366. }
  1367. continue;
  1368. }
  1369. }
  1370. else if (ch == separator)
  1371. {
  1372. // Don't allow separators before we see digit characters of phase
  1373. // 1, and don't allow separators in the second pattern (j == 0).
  1374. if (phase == 0 || j == 0)
  1375. throw new IllegalArgumentException("Unquoted special character '" +
  1376. ch + "' in pattern \"" +
  1377. pattern + '"');
  1378. start = pos + 1;
  1379. pos = pattern.length();
  1380. continue;
  1381. }
  1382. // Next handle characters which are appended directly.
  1383. else if (ch == percent)
  1384. {
  1385. if (multiplier != 1)
  1386. throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1387. pattern + '"');
  1388. multiplier = 100;
  1389. ch = symbols.getPercent();
  1390. }
  1391. else if (ch == perMill)
  1392. {
  1393. if (multiplier != 1)
  1394. throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1395. pattern + '"');
  1396. multiplier = 1000;
  1397. ch = symbols.getPerMill();
  1398. }
  1399. }
  1400. // Note that if we are within quotes, or if this is an unquoted,
  1401. // non-special character, then we usually fall through to here.
  1402. affix.append(ch);
  1403. break;
  1404. case 1:
  1405. // Phase one must be identical in the two sub-patterns. We
  1406. // enforce this by doing a direct comparison. While
  1407. // processing the first sub-pattern, we just record its
  1408. // length. While processing the second, we compare
  1409. // characters.
  1410. if (j == 1) ++phaseOneLength;
  1411. else
  1412. {
  1413. /**
  1414. * 1.2 Back-out comment : HShih
  1415. * if (ch != pattern.charAt(phaseOneStart++))
  1416. * throw new IllegalArgumentException("Subpattern mismatch in \"" +
  1417. * pattern + '"');
  1418. * phaseTwo = true;
  1419. */
  1420. if (--phaseOneLength == 0)
  1421. {
  1422. phase = 2;
  1423. affix = suffix;
  1424. }
  1425. continue;
  1426. }
  1427. // Process the digits, decimal, and grouping characters. We
  1428. // record five pieces of information. We expect the digits
  1429. // to occur in the pattern ####0000.####, and we record the
  1430. // number of left digits, zero (central) digits, and right
  1431. // digits. The position of the last grouping character is
  1432. // recorded (should be somewhere within the first two blocks
  1433. // of characters), as is the position of the decimal point,
  1434. // if any (should be in the zero digits). If there is no
  1435. // decimal point, then there should be no right digits.
  1436. if (ch == digit)
  1437. {
  1438. if (zeroDigitCount > 0) ++digitRightCount; else ++digitLeftCount;
  1439. if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1440. }
  1441. else if (ch == zeroDigit)
  1442. {
  1443. if (digitRightCount > 0)
  1444. throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
  1445. pattern + '"');
  1446. ++zeroDigitCount;
  1447. if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1448. }
  1449. else if (ch == groupingSeparator)
  1450. {
  1451. groupingCount = 0;
  1452. }
  1453. else if (ch == decimalSeparator)
  1454. {
  1455. if (decimalPos >= 0)
  1456. throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
  1457. pattern + '"');
  1458. decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
  1459. }
  1460. else if (ch == exponent)
  1461. {
  1462. if (useExponentialNotation)
  1463. throw new IllegalArgumentException("Multiple exponential " +
  1464. "symbols in pattern \"" +
  1465. pattern + '"');
  1466. useExponentialNotation = true;
  1467. minExponentDigits = 0;
  1468. // Use lookahead to parse out the exponential part of the
  1469. // pattern, then jump into phase 2.
  1470. while (++pos < pattern.length() &&
  1471. pattern.charAt(pos) == zeroDigit)
  1472. {
  1473. ++minExponentDigits;
  1474. ++phaseOneLength;
  1475. }
  1476. if ((digitLeftCount + zeroDigitCount) < 1 ||
  1477. minExponentDigits < 1)
  1478. throw new IllegalArgumentException("Malformed exponential " +
  1479. "pattern \"" +
  1480. pattern + '"');
  1481. // Transition to phase 2
  1482. phase = 2;
  1483. affix = suffix;
  1484. --pos;
  1485. continue;
  1486. }
  1487. else
  1488. {
  1489. phase = 2;
  1490. affix = suffix;
  1491. --pos;
  1492. --phaseOneLength;
  1493. continue;
  1494. }
  1495. break;
  1496. }
  1497. }
  1498. /**
  1499. * 1.2 Back-out comment : HShih
  1500. * if (phaseTwo && phaseOneLength > 0)
  1501. * throw new IllegalArgumentException("Subpattern mismatch in \"" +
  1502. * pattern + '"');
  1503. */
  1504. // Handle patterns with no '0' pattern character. These patterns
  1505. // are legal, but must be interpreted. "##.###" -> "#0.###".
  1506. // ".###" -> ".0##".
  1507. /* We allow patterns of the form "####" to produce a zeroDigitCount of
  1508. * zero (got that?); although this seems like it might make it possible
  1509. * for format() to produce empty strings, format() checks for this
  1510. * condition and outputs a zero digit in this situation. Having a
  1511. * zeroDigitCount of zero yields a minimum integer digits of zero, which
  1512. * allows proper round-trip patterns. That is, we don't want "#" to
  1513. * become "#0" when toPattern() is called (even though that's what it
  1514. * really is, semantically). */
  1515. if (zeroDigitCount == 0 && digitLeftCount > 0 &&
  1516. decimalPos >= 0) {
  1517. // Handle "###.###" and "###." and ".###"
  1518. int n = decimalPos;
  1519. if (n == 0) ++n; // Handle ".###"
  1520. digitRightCount = digitLeftCount - n;
  1521. digitLeftCount = n - 1;
  1522. zeroDigitCount = 1;
  1523. }
  1524. // Do syntax checking on the digits.
  1525. if ((decimalPos < 0 && digitRightCount > 0) ||
  1526. (decimalPos >= 0 &&
  1527. (decimalPos < digitLeftCount ||
  1528. decimalPos > (digitLeftCount + zeroDigitCount))) ||
  1529. groupingCount == 0 ||
  1530. inQuote)
  1531. throw new IllegalArgumentException("Malformed pattern \"" +
  1532. pattern + '"');
  1533. if (j == 1) {
  1534. this.positivePrefix = prefix.toString();
  1535. this.positiveSuffix = suffix.toString();
  1536. this.negativePrefix = positivePrefix; // assume these for now
  1537. this.negativeSuffix = positiveSuffix;
  1538. int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
  1539. /* The effectiveDecimalPos is the position the decimal is at or
  1540. * would be at if there is no decimal. Note that if decimalPos<0,
  1541. * then digitTotalCount == digitLeftCount + zeroDigitCount. */
  1542. int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
  1543. setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
  1544. setMaximumIntegerDigits(useExponentialNotation ?
  1545. digitLeftCount + getMinimumIntegerDigits() : DOUBLE_INTEGER_DIGITS);
  1546. setMaximumFractionDigits(decimalPos >= 0 ? (digitTotalCount - decimalPos) : 0);
  1547. setMinimumFractionDigits(decimalPos >= 0 ?
  1548. (digitLeftCount + zeroDigitCount - decimalPos) : 0);
  1549. setGroupingUsed(groupingCount > 0);
  1550. this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
  1551. this.multiplier = multiplier;
  1552. setDecimalSeparatorAlwaysShown(decimalPos == 0 || decimalPos == digitTotalCount);
  1553. } else {
  1554. this.negativePrefix = prefix.toString();
  1555. this.negativeSuffix = suffix.toString();
  1556. gotNegative = true;
  1557. }
  1558. }
  1559. // If there was no negative pattern, or if the negative pattern is identical
  1560. // to the positive pattern, then prepend the minus sign to the positive
  1561. // pattern to form the negative pattern.
  1562. if (!gotNegative ||
  1563. (negativePrefix.equals(positivePrefix)
  1564. && negativeSuffix.equals(positiveSuffix))) {
  1565. negativeSuffix = positiveSuffix;
  1566. negativePrefix = symbols.getMinusSign() + positivePrefix;
  1567. }
  1568. }
  1569. /**
  1570. * Sets the maximum number of digits allowed in the integer portion of a
  1571. * number. This override limits the integer digit count to 309.
  1572. * @see NumberFormat#setMaximumIntegerDigits
  1573. */
  1574. public void setMaximumIntegerDigits(int newValue) {
  1575. super.setMaximumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
  1576. }
  1577. /**
  1578. * Sets the minimum number of digits allowed in the integer portion of a
  1579. * number. This override limits the integer digit count to 309.
  1580. * @see NumberFormat#setMinimumIntegerDigits
  1581. */
  1582. public void setMinimumIntegerDigits(int newValue) {
  1583. super.setMinimumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
  1584. }
  1585. /**
  1586. * Sets the maximum number of digits allowed in the fraction portion of a
  1587. * number. This override limits the fraction digit count to 340.
  1588. * @see NumberFormat#setMaximumFractionDigits
  1589. */
  1590. public void setMaximumFractionDigits(int newValue) {
  1591. super.setMaximumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
  1592. }
  1593. /**
  1594. * Sets the minimum number of digits allowed in the fraction portion of a
  1595. * number. This override limits the fraction digit count to 340.
  1596. * @see NumberFormat#setMinimumFractionDigits
  1597. */
  1598. public void setMinimumFractionDigits(int newValue) {
  1599. super.setMinimumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
  1600. }
  1601. /**
  1602. * First, read the default serializable fields from the stream. Then
  1603. * if <code>serialVersionOnStream</code> is less than 1, indicating that
  1604. * the stream was written by JDK 1.1, initialize <code>useExponentialNotation</code>
  1605. * to false, since it was not present in JDK 1.1.
  1606. * Finally, set serialVersionOnStream back to the maximum allowed value so that
  1607. * default serialization will work properly if this object is streamed out again.
  1608. */
  1609. private void readObject(ObjectInputStream stream)
  1610. throws IOException, ClassNotFoundException
  1611. {
  1612. stream.defaultReadObject();
  1613. if (serialVersionOnStream < 1) {
  1614. // Didn't have exponential fields
  1615. useExponentialNotation = false;
  1616. }
  1617. serialVersionOnStream = currentSerialVersion;
  1618. digitList = new DigitList();
  1619. }
  1620. //----------------------------------------------------------------------
  1621. // INSTANCE VARIABLES
  1622. //----------------------------------------------------------------------
  1623. private transient DigitList digitList = new DigitList();
  1624. /**
  1625. * The symbol used as a prefix when formatting positive numbers, e.g. "+".
  1626. *
  1627. * @serial
  1628. * @see #getPositivePrefix
  1629. */
  1630. private String positivePrefix = "";
  1631. /**
  1632. * The symbol used as a suffix when formatting positive numbers.
  1633. * This is often an empty string.
  1634. *
  1635. * @serial
  1636. * @see #getPositiveSuffix
  1637. */
  1638. private String positiveSuffix = "";
  1639. /**
  1640. * The symbol used as a prefix when formatting negative numbers, e.g. "-".
  1641. *
  1642. * @serial
  1643. * @see #getNegativePrefix
  1644. */
  1645. private String negativePrefix = "-";
  1646. /**
  1647. * The symbol used as a suffix when formatting negative numbers.
  1648. * This is often an empty string.
  1649. *
  1650. * @serial
  1651. * @see #getNegativeSuffix
  1652. */
  1653. private String negativeSuffix = "";
  1654. /**
  1655. * The multiplier for use in percent, permill, etc.
  1656. *
  1657. * @serial
  1658. * @see #getMultiplier
  1659. */
  1660. private int multiplier = 1;
  1661. /**
  1662. * The number of digits between grouping separators in the integer
  1663. * portion of a number. Must be greater than 0 if
  1664. * <code>NumberFormat.groupingUsed</code> is true.
  1665. *
  1666. * @serial
  1667. * @see #getGroupingSize
  1668. * @see java.text.NumberFormat#isGroupingUsed
  1669. */
  1670. private byte groupingSize = 3; // invariant, > 0 if useThousands
  1671. /**
  1672. * If true, forces the decimal separator to always appear in a formatted
  1673. * number, even if the fractional part of the number is zero.
  1674. *
  1675. * @serial
  1676. * @see #isDecimalSeparatorAlwaysShown
  1677. */
  1678. private boolean decimalSeparatorAlwaysShown = false;
  1679. /**
  1680. * True if this object represents a currency format. This determines
  1681. * whether the monetary decimal separator is used instead of the normal one.
  1682. */
  1683. private transient boolean isCurrencyFormat = false;
  1684. /**
  1685. * The <code>DecimalFormatSymbols</code> object used by this format.
  1686. * It contains the symbols used to format numbers, e.g. the grouping separator,
  1687. * decimal separator, and so on.
  1688. *
  1689. * @serial
  1690. * @see #setDecimalFormatSymbols
  1691. * @see java.text.DecimalFormatSymbols
  1692. */
  1693. private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
  1694. /**
  1695. * True to force the use of exponential (i.e. scientific) notation when formatting
  1696. * numbers.
  1697. * <p>
  1698. * Note that the JDK 1.2 public API provides no way to set this field,
  1699. * even though it is supported by the implementation and the stream format.
  1700. * The intent is that this will be added to the API in the future.
  1701. *
  1702. * @serial
  1703. * @since JDK 1.2
  1704. */
  1705. private boolean useExponentialNotation; // Newly persistent in JDK 1.2
  1706. /**
  1707. * The minimum number of digits used to display the exponent when a number is
  1708. * formatted in exponential notation. This field is ignored if
  1709. * <code>useExponentialNotation</code> is not true.
  1710. * <p>
  1711. * Note that the JDK 1.2 public API provides no way to set this field,
  1712. * even though it is supported by the implementation and the stream format.
  1713. * The intent is that this will be added to the API in the future.
  1714. *
  1715. * @serial
  1716. * @since JDK 1.2
  1717. */
  1718. private byte minExponentDigits; // Newly persistent in JDK 1.2
  1719. //----------------------------------------------------------------------
  1720. static final int currentSerialVersion = 1;
  1721. /**
  1722. * The internal serial version which says which version was written
  1723. * Possible values are:
  1724. * <ul>
  1725. * <li><b>0</b> (default): versions before JDK 1.2
  1726. * <li><b>1</b>: version from JDK 1.2 and later, which includes the two new fields
  1727. * <code>useExponentialNotation</code> and <code>minExponentDigits</code>.
  1728. * </ul>
  1729. * @since JDK 1.2
  1730. * @serial
  1731. */
  1732. private int serialVersionOnStream = currentSerialVersion;
  1733. //----------------------------------------------------------------------
  1734. // CONSTANTS
  1735. //----------------------------------------------------------------------
  1736. // Constants for characters used in programmatic (unlocalized) patterns.
  1737. private static final char PATTERN_ZERO_DIGIT = '0';
  1738. private static final char PATTERN_GROUPING_SEPARATOR = ',';
  1739. private static final char PATTERN_DECIMAL_SEPARATOR = '.';
  1740. private static final char PATTERN_PER_MILLE = '\u2030';
  1741. private static final char PATTERN_PERCENT = '%';
  1742. private static final char PATTERN_DIGIT = '#';
  1743. private static final char PATTERN_SEPARATOR = ';';
  1744. private static final char PATTERN_EXPONENT = 'E';
  1745. /**
  1746. * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
  1747. * is used in patterns and substitued with either the currency symbol,
  1748. * or if it is doubled, with the international currency symbol. If the
  1749. * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
  1750. * replaced with the monetary decimal separator.
  1751. *
  1752. * The CURRENCY_SIGN is not localized.
  1753. */
  1754. private static final char CURRENCY_SIGN = '\u00A4';
  1755. private static final char QUOTE = '\'';
  1756. // Upper limit on integer and fraction digits for a Java double
  1757. static final int DOUBLE_INTEGER_DIGITS = 309;
  1758. static final int DOUBLE_FRACTION_DIGITS = 340;
  1759. // Proclaim JDK 1.1 serial compatibility.
  1760. static final long serialVersionUID = 864413376551465018L;
  1761. /**
  1762. * Cache to hold the NumberPattern of a Locale.
  1763. */
  1764. private static Hashtable cachedLocaleData = new Hashtable(3);
  1765. }
  1766. //eof