0001: /*
0002: *
0003: * @(#)DecimalFormat.java 1.71 06/10/10
0004: *
0005: * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights
0006: * Reserved. Use is subject to license terms.
0007: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0008: *
0009: * This program is free software; you can redistribute it and/or
0010: * modify it under the terms of the GNU General Public License version
0011: * 2 only, as published by the Free Software Foundation.
0012: *
0013: * This program is distributed in the hope that it will be useful, but
0014: * WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0016: * General Public License version 2 for more details (a copy is
0017: * included at /legal/license.txt).
0018: *
0019: * You should have received a copy of the GNU General Public License
0020: * version 2 along with this work; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0022: * 02110-1301 USA
0023: *
0024: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0025: * Clara, CA 95054 or visit www.sun.com if you need additional
0026: * information or have any questions.
0027: */
0028:
0029: /*
0030: * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
0031: * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
0032: *
0033: * The original version of this source code and documentation is copyrighted
0034: * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
0035: * materials are provided under terms of a License Agreement between Taligent
0036: * and Sun. This technology is protected by multiple US and International
0037: * patents. This notice and attribution to Taligent may not be removed.
0038: * Taligent is a registered trademark of Taligent, Inc.
0039: *
0040: */
0041:
0042: package java.text;
0043:
0044: import java.io.InvalidObjectException;
0045: import java.io.IOException;
0046: import java.io.ObjectInputStream;
0047: import java.math.BigInteger;
0048: import java.util.ArrayList;
0049: import java.util.Currency;
0050: import java.util.Hashtable;
0051: import java.util.Locale;
0052: import java.util.ResourceBundle;
0053: import sun.text.resources.LocaleData;
0054:
0055: /**
0056: * <code>DecimalFormat</code> is a concrete subclass of
0057: * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
0058: * features designed to make it possible to parse and format numbers in any
0059: * locale, including support for Western, Arabic, and Indic digits. It also
0060: * supports different kinds of numbers, including integers (123), fixed-point
0061: * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
0062: * currency amounts ($123). All of these can be localized.
0063: *
0064: * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
0065: * default locale, call one of <code>NumberFormat</code>'s factory methods, such
0066: * as <code>getInstance()</code>. In general, do not call the
0067: * <code>DecimalFormat</code> constructors directly, since the
0068: * <code>NumberFormat</code> factory methods may return subclasses other than
0069: * <code>DecimalFormat</code>. If you need to customize the format object, do
0070: * something like this:
0071: *
0072: * <blockquote><pre>
0073: * NumberFormat f = NumberFormat.getInstance(loc);
0074: * if (f instanceof DecimalFormat) {
0075: * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
0076: * }
0077: * </pre></blockquote>
0078: *
0079: * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
0080: * <em>symbols</em>. The pattern may be set directly using
0081: * <code>applyPattern()</code>, or indirectly using the API methods. The
0082: * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
0083: * the <code>NumberFormat</code> factory methods, the pattern and symbols are
0084: * read from localized <code>ResourceBundle</code>s.
0085: *
0086: * <h4>Patterns</h4>
0087: *
0088: * <code>DecimalFormat</code> patterns have the following syntax:
0089: * <blockquote><pre>
0090: * <i>Pattern:</i>
0091: * <i>PositivePattern</i>
0092: * <i>PositivePattern</i> ; <i>NegativePattern</i>
0093: * <i>PositivePattern:</i>
0094: * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
0095: * <i>NegativePattern:</i>
0096: * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
0097: * <i>Prefix:</i>
0098: * any Unicode characters except \uFFFE, \uFFFF, and special characters
0099: * <i>Suffix:</i>
0100: * any Unicode characters except \uFFFE, \uFFFF, and special characters
0101: * <i>Number:</i>
0102: * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
0103: * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
0104: * <i>Integer:</i>
0105: * <i>MinimumInteger</i>
0106: * #
0107: * # <i>Integer</i>
0108: * # , <i>Integer</i>
0109: * <i>MinimumInteger:</i>
0110: * 0
0111: * 0 <i>MinimumInteger</i>
0112: * 0 , <i>MinimumInteger</i>
0113: * <i>Fraction:</i>
0114: * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
0115: * <i>MinimumFraction:</i>
0116: * 0 <i>MinimumFraction<sub>opt</sub></i>
0117: * <i>OptionalFraction:</i>
0118: * # <i>OptionalFraction<sub>opt</sub></i>
0119: * <i>Exponent:</i>
0120: * E <i>MinimumExponent</i>
0121: * <i>MinimumExponent:</i>
0122: * 0 <i>MinimumExponent<sub>opt</sub></i>
0123: * </pre></blockquote>
0124: *
0125: * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
0126: * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
0127: * subpattern has a prefix, numeric part, and suffix. The negative subpattern
0128: * is optional; if absent, then the positive subpattern prefixed with the
0129: * localized minus sign (code>'-'</code> in most locales) is used as the
0130: * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
0131: * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
0132: * serves only to specify the negative prefix and suffix; the number of digits,
0133: * minimal digits, and other characteristics are all the same as the positive
0134: * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
0135: * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
0136: *
0137: * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
0138: * thousands separators, decimal separators, etc. may be set to arbitrary
0139: * values, and they will appear properly during formatting. However, care must
0140: * be taken that the symbols and strings do not conflict, or parsing will be
0141: * unreliable. For example, either the positive and negative prefixes or the
0142: * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
0143: * to distinguish positive from negative values. (If they are identical, then
0144: * <code>DecimalFormat</code> will behave as if no negative subpattern was
0145: * specified.) Another example is that the decimal separator and thousands
0146: * separator should be distinct characters, or parsing will be impossible.
0147: *
0148: * <p>The grouping separator is commonly used for thousands, but in some
0149: * countries it separates ten-thousands. The grouping size is a constant number
0150: * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
0151: * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
0152: * interval between the last one and the end of the integer is the one that is
0153: * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
0154: * <code>"##,####,####"</code>.
0155: *
0156: * <h4>Special Pattern Characters</h4>
0157: *
0158: * <p>Many characters in a pattern are taken literally; they are matched during
0159: * parsing and output unchanged during formatting. Special characters, on the
0160: * other hand, stand for other characters, strings, or classes of characters.
0161: * They must be quoted, unless noted otherwise, if they are to appear in the
0162: * prefix or suffix as literals.
0163: *
0164: * <p>The characters listed here are used in non-localized patterns. Localized
0165: * patterns use the corresponding characters taken from this formatter's
0166: * <code>DecimalFormatSymbols</code> object instead, and these characters lose
0167: * their special status. Two exceptions are the currency sign and quote, which
0168: * are not localized.
0169: *
0170: * <blockquote>
0171: * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
0172: * location, localized, and meaning.">
0173: * <tr bgcolor="#ccccff">
0174: * <th align=left>Symbol
0175: * <th align=left>Location
0176: * <th align=left>Localized?
0177: * <th align=left>Meaning
0178: * <tr valign=top>
0179: * <td><code>0</code>
0180: * <td>Number
0181: * <td>Yes
0182: * <td>Digit
0183: * <tr valign=top bgcolor="#eeeeff">
0184: * <td><code>#</code>
0185: * <td>Number
0186: * <td>Yes
0187: * <td>Digit, zero shows as absent
0188: * <tr valign=top>
0189: * <td><code>.</code>
0190: * <td>Number
0191: * <td>Yes
0192: * <td>Decimal separator or monetary decimal separator
0193: * <tr valign=top bgcolor="#eeeeff">
0194: * <td><code>-</code>
0195: * <td>Number
0196: * <td>Yes
0197: * <td>Minus sign
0198: * <tr valign=top>
0199: * <td><code>,</code>
0200: * <td>Number
0201: * <td>Yes
0202: * <td>Grouping separator
0203: * <tr valign=top bgcolor="#eeeeff">
0204: * <td><code>E</code>
0205: * <td>Number
0206: * <td>Yes
0207: * <td>Separates mantissa and exponent in scientific notation.
0208: * <em>Need not be quoted in prefix or suffix.</em>
0209: * <tr valign=top>
0210: * <td><code>;</code>
0211: * <td>Subpattern boundary
0212: * <td>Yes
0213: * <td>Separates positive and negative subpatterns
0214: * <tr valign=top bgcolor="#eeeeff">
0215: * <td><code>%</code>
0216: * <td>Prefix or suffix
0217: * <td>Yes
0218: * <td>Multiply by 100 and show as percentage
0219: * <tr valign=top>
0220: * <td><code>\u2030</code>
0221: * <td>Prefix or suffix
0222: * <td>Yes
0223: * <td>Multiply by 1000 and show as per mille
0224: * <tr valign=top bgcolor="#eeeeff">
0225: * <td><code>¤</code> (<code>\u00A4</code>)
0226: * <td>Prefix or suffix
0227: * <td>No
0228: * <td>Currency sign, replaced by currency symbol. If
0229: * doubled, replaced by international currency symbol.
0230: * If present in a pattern, the monetary decimal separator
0231: * is used instead of the decimal separator.
0232: * <tr valign=top>
0233: * <td><code>'</code>
0234: * <td>Prefix or suffix
0235: * <td>No
0236: * <td>Used to quote special characters in a prefix or suffix,
0237: * for example, <code>"'#'#"</code> formats 123 to
0238: * <code>"#123"</code>. To create a single quote
0239: * itself, use two in a row: <code>"# o''clock"</code>.
0240: * </table>
0241: * </blockquote>
0242: *
0243: * <h4>Scientific Notation</h4>
0244: *
0245: * <p>Numbers in scientific notation are expressed as the product of a mantissa
0246: * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
0247: * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
0248: * <code>DecimalFormat</code> can be instructed to format and parse scientific
0249: * notation <em>only via a pattern</em>; there is currently no factory method
0250: * that creates a scientific notation format. In a pattern, the exponent
0251: * character immediately followed by one or more digit characters indicates
0252: * scientific notation. Example: <code>"0.###E0"</code> formats the number
0253: * 1234 as <code>"1.234E3"</code>.
0254: *
0255: * <ul>
0256: * <li>The number of digit characters after the exponent character gives the
0257: * minimum exponent digit count. There is no maximum. Negative exponents are
0258: * formatted using the localized minus sign, <em>not</em> the prefix and suffix
0259: * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
0260: *
0261: * <li>The minimum and maximum number of integer digits are interpreted
0262: * together:
0263: *
0264: * <ul>
0265: * <li>If the maximum number of integer digits is greater than their minimum number
0266: * and greater than 1, it forces the exponent to be a multiple of the maximum
0267: * number of integer digits, and the minimum number of integer digits to be
0268: * interpreted as 1. The most common use of this is to generate
0269: * <em>engineering notation</em>, in which the exponent is a multiple of three,
0270: * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
0271: * formats to <code>"12.345E3"</code>, and 123456 formats to
0272: * <code>"123.456E3"</code>.
0273: *
0274: * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
0275: * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
0276: * <code>"12.3E-4"</code>.
0277: * </ul>
0278: *
0279: * <li>The number of significant digits in the mantissa is the sum of the
0280: * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
0281: * unaffected by the maximum integer digits. For example, 12345 formatted with
0282: * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
0283: * the significant digits count to zero. The number of significant digits
0284: * does not affect parsing.
0285: *
0286: * <li>Exponential patterns may not contain grouping separators.
0287: * </ul>
0288: *
0289: * <h4>Rounding</h4>
0290: *
0291: * <code>DecimalFormat</code> uses half-even rounding (see
0292: * {@link java.math.BigDecimal#ROUND_HALF_EVEN ROUND_HALF_EVEN}) for
0293: * formatting.
0294: *
0295: * <h4>Digits</h4>
0296: *
0297: * For formatting, <code>DecimalFormat</code> uses the ten consecutive
0298: * characters starting with the localized zero digit defined in the
0299: * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
0300: * digits as well as all Unicode decimal digits, as defined by
0301: * {@link Character#digit Character.digit}, are recognized.
0302: *
0303: * <h4>Special Values</h4>
0304: *
0305: * <p><code>NaN</code> is formatted as a single character, typically
0306: * <code>\uFFFD</code>. This character is determined by the
0307: * <code>DecimalFormatSymbols</code> object. This is the only value for which
0308: * the prefixes and suffixes are not used.
0309: *
0310: * <p>Infinity is formatted as a single character, typically
0311: * <code>\u221E</code>, with the positive or negative prefixes and suffixes
0312: * applied. The infinity character is determined by the
0313: * <code>DecimalFormatSymbols</code> object.
0314: *
0315: * <p>Negative zero (<code>"-0"</code>) parses to <code>Double(-0.0)</code>,
0316: * unless <code>isParseIntegerOnly()</code> is true, in which case it parses to
0317: * <code>Long(0)</code>.
0318: *
0319: * <h4><a name="synchronization">Synchronization</a></h4>
0320: *
0321: * <p>
0322: * Decimal formats are generally not synchronized.
0323: * It is recommended to create separate format instances for each thread.
0324: * If multiple threads access a format concurrently, it must be synchronized
0325: * externally.
0326: *
0327: * <h4>Example</h4>
0328: *
0329: * <blockquote><pre>
0330: * <strong>// Print out a number using the localized number, integer, currency,
0331: * // and percent format for each locale</strong>
0332: * Locale[] locales = NumberFormat.getAvailableLocales();
0333: * double myNumber = -1234.56;
0334: * NumberFormat form;
0335: * for (int j=0; j<4; ++j) {
0336: * System.out.println("FORMAT");
0337: * for (int i = 0; i < locales.length; ++i) {
0338: * if (locales[i].getCountry().length() == 0) {
0339: * continue; // Skip language-only locales
0340: * }
0341: * System.out.print(locales[i].getDisplayName());
0342: * switch (j) {
0343: * case 0:
0344: * form = NumberFormat.getInstance(locales[i]); break;
0345: * case 1:
0346: * form = NumberFormat.getIntegerInstance(locales[i]); break;
0347: * case 2:
0348: * form = NumberFormat.getCurrencyInstance(locales[i]); break;
0349: * default:
0350: * form = NumberFormat.getPercentInstance(locales[i]); break;
0351: * }
0352: * if (form instanceof DecimalFormat) {
0353: * System.out.print(": " + ((DecimalFormat) form).toPattern());
0354: * }
0355: * System.out.print(" -> " + form.format(myNumber));
0356: * try {
0357: * System.out.println(" -> " + form.parse(form.format(myNumber)));
0358: * } catch (ParseException e) {}
0359: * }
0360: * }
0361: * </pre></blockquote>
0362: *
0363: * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
0364: * @see NumberFormat
0365: * @see DecimalFormatSymbols
0366: * @see ParsePosition
0367: * @version 1.65, 01/12/04
0368: * @author Mark Davis
0369: * @author Alan Liu
0370: */
0371: public class DecimalFormat extends NumberFormat {
0372:
0373: /**
0374: * Creates a DecimalFormat using the default pattern and symbols
0375: * for the default locale. This is a convenient way to obtain a
0376: * DecimalFormat when internationalization is not the main concern.
0377: * <p>
0378: * To obtain standard formats for a given locale, use the factory methods
0379: * on NumberFormat such as getNumberInstance. These factories will
0380: * return the most appropriate sub-class of NumberFormat for a given
0381: * locale.
0382: *
0383: * @see java.text.NumberFormat#getInstance
0384: * @see java.text.NumberFormat#getNumberInstance
0385: * @see java.text.NumberFormat#getCurrencyInstance
0386: * @see java.text.NumberFormat#getPercentInstance
0387: */
0388: public DecimalFormat() {
0389: Locale def = Locale.getDefault();
0390: // try to get the pattern from the cache
0391: String pattern = (String) cachedLocaleData.get(def);
0392: if (pattern == null) { /* cache miss */
0393: // Get the pattern for the default locale.
0394: ResourceBundle rb = LocaleData.getLocaleElements(def);
0395: String[] all = rb.getStringArray("NumberPatterns");
0396: pattern = all[0];
0397: /* update cache */
0398: cachedLocaleData.put(def, pattern);
0399: }
0400:
0401: // Always applyPattern after the symbols are set
0402: this .symbols = new DecimalFormatSymbols(def);
0403: applyPattern(pattern, false);
0404: }
0405:
0406: /**
0407: * Creates a DecimalFormat using the given pattern and the symbols
0408: * for the default locale. This is a convenient way to obtain a
0409: * DecimalFormat when internationalization is not the main concern.
0410: * <p>
0411: * To obtain standard formats for a given locale, use the factory methods
0412: * on NumberFormat such as getNumberInstance. These factories will
0413: * return the most appropriate sub-class of NumberFormat for a given
0414: * locale.
0415: *
0416: * @param pattern A non-localized pattern string.
0417: * @exception NullPointerException if <code>pattern</code> is null
0418: * @exception IllegalArgumentException if the given pattern is invalid.
0419: * @see java.text.NumberFormat#getInstance
0420: * @see java.text.NumberFormat#getNumberInstance
0421: * @see java.text.NumberFormat#getCurrencyInstance
0422: * @see java.text.NumberFormat#getPercentInstance
0423: */
0424: public DecimalFormat(String pattern) {
0425: // Always applyPattern after the symbols are set
0426: this .symbols = new DecimalFormatSymbols(Locale.getDefault());
0427: applyPattern(pattern, false);
0428: }
0429:
0430: /**
0431: * Creates a DecimalFormat using the given pattern and symbols.
0432: * Use this constructor when you need to completely customize the
0433: * behavior of the format.
0434: * <p>
0435: * To obtain standard formats for a given
0436: * locale, use the factory methods on NumberFormat such as
0437: * getInstance or getCurrencyInstance. If you need only minor adjustments
0438: * to a standard format, you can modify the format returned by
0439: * a NumberFormat factory method.
0440: *
0441: * @param pattern a non-localized pattern string
0442: * @param symbols the set of symbols to be used
0443: * @exception NullPointerException if any of the given arguments is null
0444: * @exception IllegalArgumentException if the given pattern is invalid
0445: * @see java.text.NumberFormat#getInstance
0446: * @see java.text.NumberFormat#getNumberInstance
0447: * @see java.text.NumberFormat#getCurrencyInstance
0448: * @see java.text.NumberFormat#getPercentInstance
0449: * @see java.text.DecimalFormatSymbols
0450: */
0451: public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
0452: // Always applyPattern after the symbols are set
0453: this .symbols = (DecimalFormatSymbols) symbols.clone();
0454: applyPattern(pattern, false);
0455: }
0456:
0457: // Overrides
0458: /**
0459: * Formats a double to produce a string.
0460: * @param number The double to format
0461: * @param result where the text is to be appended
0462: * @param fieldPosition On input: an alignment field, if desired.
0463: * On output: the offsets of the alignment field.
0464: * @return The formatted number string
0465: * @see java.text.FieldPosition
0466: */
0467: public StringBuffer format(double number, StringBuffer result,
0468: FieldPosition fieldPosition) {
0469: fieldPosition.setBeginIndex(0);
0470: fieldPosition.setEndIndex(0);
0471: return format(number, result, fieldPosition.getFieldDelegate());
0472: }
0473:
0474: /**
0475: * Formats a double to produce a string.
0476: * @param number The double to format
0477: * @param result where the text is to be appended
0478: * @param delegate notified of locations of sub fields
0479: * @return The formatted number string
0480: */
0481: private StringBuffer format(double number, StringBuffer result,
0482: FieldDelegate delegate) {
0483: if (Double.isNaN(number)) {
0484: int iFieldStart = result.length();
0485:
0486: result.append(symbols.getNaN());
0487:
0488: delegate
0489: .formatted(INTEGER_FIELD, Field.INTEGER,
0490: Field.INTEGER, iFieldStart,
0491: result.length(), result);
0492: return result;
0493: }
0494:
0495: /* Detecting whether a double is negative is easy with the exception of
0496: * the value -0.0. This is a double which has a zero mantissa (and
0497: * exponent), but a negative sign bit. It is semantically distinct from
0498: * a zero with a positive sign bit, and this distinction is important
0499: * to certain kinds of computations. However, it's a little tricky to
0500: * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
0501: * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
0502: * -Infinity. Proper detection of -0.0 is needed to deal with the
0503: * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
0504: */
0505: boolean isNegative = (number < 0.0)
0506: || (number == 0.0 && 1 / number < 0.0);
0507: if (isNegative)
0508: number = -number;
0509:
0510: // Do this BEFORE checking to see if value is infinite!
0511: if (multiplier != 1)
0512: number *= multiplier;
0513:
0514: if (Double.isInfinite(number)) {
0515: if (isNegative) {
0516: append(result, negativePrefix, delegate,
0517: getNegativePrefixFieldPositions(), Field.SIGN);
0518: } else {
0519: append(result, positivePrefix, delegate,
0520: getPositivePrefixFieldPositions(), Field.SIGN);
0521: }
0522: int iFieldStart = result.length();
0523:
0524: result.append(symbols.getInfinity());
0525:
0526: delegate
0527: .formatted(INTEGER_FIELD, Field.INTEGER,
0528: Field.INTEGER, iFieldStart,
0529: result.length(), result);
0530:
0531: if (isNegative) {
0532: append(result, negativeSuffix, delegate,
0533: getNegativeSuffixFieldPositions(), Field.SIGN);
0534: } else {
0535: append(result, positiveSuffix, delegate,
0536: getPositiveSuffixFieldPositions(), Field.SIGN);
0537: }
0538: return result;
0539: }
0540:
0541: // At this point we are guaranteed a nonnegative finite
0542: // number.
0543: synchronized (digitList) {
0544: digitList.set(number,
0545: useExponentialNotation ? getMaximumIntegerDigits()
0546: + getMaximumFractionDigits()
0547: : getMaximumFractionDigits(),
0548: !useExponentialNotation);
0549:
0550: return subformat(result, delegate, isNegative, false);
0551: }
0552: }
0553:
0554: /**
0555: * Format a long to produce a string.
0556: * @param number The long to format
0557: * @param result where the text is to be appended
0558: * @param fieldPosition On input: an alignment field, if desired.
0559: * On output: the offsets of the alignment field.
0560: * @return The formatted number string
0561: * @see java.text.FieldPosition
0562: */
0563: public StringBuffer format(long number, StringBuffer result,
0564: FieldPosition fieldPosition) {
0565: fieldPosition.setBeginIndex(0);
0566: fieldPosition.setEndIndex(0);
0567:
0568: return format(number, result, fieldPosition.getFieldDelegate());
0569: }
0570:
0571: /**
0572: * Format a long to produce a string.
0573: * @param number The long to format
0574: * @param result where the text is to be appended
0575: * @param delegate notified of locations of sub fields
0576: * @return The formatted number string
0577: * @see java.text.FieldPosition
0578: */
0579: private StringBuffer format(long number, StringBuffer result,
0580: FieldDelegate delegate) {
0581: boolean isNegative = (number < 0);
0582: if (isNegative)
0583: number = -number;
0584:
0585: // In general, long values always represent real finite numbers, so
0586: // we don't have to check for +/- Infinity or NaN. However, there
0587: // is one case we have to be careful of: The multiplier can push
0588: // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
0589: // check for this before multiplying, and if it happens we use doubles
0590: // instead, trading off accuracy for range.
0591: if (multiplier != 1 && multiplier != 0) {
0592: boolean useDouble = false;
0593:
0594: if (number < 0) // This can only happen if number == Long.MIN_VALUE
0595: {
0596: long cutoff = Long.MIN_VALUE / multiplier;
0597: useDouble = (number < cutoff);
0598: } else {
0599: long cutoff = Long.MAX_VALUE / multiplier;
0600: useDouble = (number > cutoff);
0601: }
0602:
0603: if (useDouble) {
0604: double dnumber = (double) (isNegative ? -number
0605: : number);
0606: return format(dnumber, result, delegate);
0607: }
0608: }
0609:
0610: number *= multiplier;
0611: synchronized (digitList) {
0612: digitList.set(number,
0613: useExponentialNotation ? getMaximumIntegerDigits()
0614: + getMaximumFractionDigits() : 0);
0615:
0616: return subformat(result, delegate, isNegative, true);
0617: }
0618: }
0619:
0620: /**
0621: * Formats an Object producing an <code>AttributedCharacterIterator</code>.
0622: * You can use the returned <code>AttributedCharacterIterator</code>
0623: * to build the resulting String, as well as to determine information
0624: * about the resulting String.
0625: * <p>
0626: * Each attribute key of the AttributedCharacterIterator will be of type
0627: * <code>NumberFormat.Field</code>, with the attribute value being the
0628: * same as the attribute key.
0629: *
0630: * @exception NullPointerException if obj is null.
0631: * @exception IllegalArgumentException when the Format cannot format the
0632: * given object.
0633: * @param obj The object to format
0634: * @return AttributedCharacterIterator describing the formatted value.
0635: * @since 1.4
0636: */
0637: public AttributedCharacterIterator formatToCharacterIterator(
0638: Object obj) {
0639: CharacterIteratorFieldDelegate delegate = new CharacterIteratorFieldDelegate();
0640: StringBuffer sb = new StringBuffer();
0641:
0642: if (obj instanceof Long
0643: || (obj instanceof BigInteger && ((BigInteger) obj)
0644: .bitLength() < 64)) {
0645: format(((Number) obj).longValue(), sb, delegate);
0646: } else if (obj == null) {
0647: throw new NullPointerException(
0648: "formatToCharacterIterator must be passed non-null object");
0649: } else if (obj instanceof Number) {
0650: format(((Number) obj).doubleValue(), sb, delegate);
0651: } else {
0652: throw new IllegalArgumentException(
0653: "Cannot format given Object as a Number");
0654: }
0655: return delegate.getIterator(sb.toString());
0656: }
0657:
0658: /**
0659: * Complete the formatting of a finite number. On entry, the digitList must
0660: * be filled in with the correct digits.
0661: */
0662: private StringBuffer subformat(StringBuffer result,
0663: FieldDelegate delegate, boolean isNegative,
0664: boolean isInteger) {
0665: // NOTE: This isn't required anymore because DigitList takes care of this.
0666: //
0667: // // The negative of the exponent represents the number of leading
0668: // // zeros between the decimal and the first non-zero digit, for
0669: // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
0670: // // is more than the maximum fraction digits, then we have an underflow
0671: // // for the printed representation. We recognize this here and set
0672: // // the DigitList representation to zero in this situation.
0673: //
0674: // if (-digitList.decimalAt >= getMaximumFractionDigits())
0675: // {
0676: // digitList.count = 0;
0677: // }
0678:
0679: char zero = symbols.getZeroDigit();
0680: int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
0681: char grouping = symbols.getGroupingSeparator();
0682: char decimal = isCurrencyFormat ? symbols
0683: .getMonetaryDecimalSeparator() : symbols
0684: .getDecimalSeparator();
0685:
0686: /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
0687: * format as zero. This allows sensible computations and preserves
0688: * relations such as signum(1/x) = signum(x), where x is +Infinity or
0689: * -Infinity. Prior to this fix, we always formatted zero values as if
0690: * they were positive. Liu 7/6/98.
0691: */
0692: if (digitList.isZero()) {
0693: digitList.decimalAt = 0; // Normalize
0694: }
0695:
0696: int fieldStart = result.length();
0697:
0698: if (isNegative) {
0699: append(result, negativePrefix, delegate,
0700: getNegativePrefixFieldPositions(), Field.SIGN);
0701: } else {
0702: append(result, positivePrefix, delegate,
0703: getPositivePrefixFieldPositions(), Field.SIGN);
0704: }
0705:
0706: if (useExponentialNotation) {
0707: int iFieldStart = result.length();
0708: int iFieldEnd = -1;
0709: int fFieldStart = -1;
0710:
0711: // Minimum integer digits are handled in exponential format by
0712: // adjusting the exponent. For example, 0.01234 with 3 minimum
0713: // integer digits is "123.4E-4".
0714:
0715: // Maximum integer digits are interpreted as indicating the
0716: // repeating range. This is useful for engineering notation, in
0717: // which the exponent is restricted to a multiple of 3. For
0718: // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
0719: // If maximum integer digits are > 1 and are larger than
0720: // minimum integer digits, then minimum integer digits are
0721: // ignored.
0722: int exponent = digitList.decimalAt;
0723: int repeat = getMaximumIntegerDigits();
0724: int minimumIntegerDigits = getMinimumIntegerDigits();
0725: if (repeat > 1 && repeat > minimumIntegerDigits) {
0726: // A repeating range is defined; adjust to it as follows.
0727: // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
0728: // -3,-4,-5=>-6, etc. This takes into account that the
0729: // exponent we have here is off by one from what we expect;
0730: // it is for the format 0.MMMMMx10^n.
0731: if (exponent >= 1) {
0732: exponent = ((exponent - 1) / repeat) * repeat;
0733: } else {
0734: // integer division rounds towards 0
0735: exponent = ((exponent - repeat) / repeat) * repeat;
0736: }
0737: minimumIntegerDigits = 1;
0738: } else {
0739: // No repeating range is defined; use minimum integer digits.
0740: exponent -= minimumIntegerDigits;
0741: }
0742:
0743: // We now output a minimum number of digits, and more if there
0744: // are more digits, up to the maximum number of digits. We
0745: // place the decimal point after the "integer" digits, which
0746: // are the first (decimalAt - exponent) digits.
0747: int minimumDigits = getMinimumIntegerDigits()
0748: + getMinimumFractionDigits();
0749: // The number of integer digits is handled specially if the number
0750: // is zero, since then there may be no digits.
0751: int integerDigits = digitList.isZero() ? minimumIntegerDigits
0752: : digitList.decimalAt - exponent;
0753: if (minimumDigits < integerDigits) {
0754: minimumDigits = integerDigits;
0755: }
0756: int totalDigits = digitList.count;
0757: if (minimumDigits > totalDigits)
0758: totalDigits = minimumDigits;
0759: boolean addedDecimalSeparator = false;
0760:
0761: for (int i = 0; i < totalDigits; ++i) {
0762: if (i == integerDigits) {
0763: // Record field information for caller.
0764: iFieldEnd = result.length();
0765:
0766: result.append(decimal);
0767: addedDecimalSeparator = true;
0768:
0769: // Record field information for caller.
0770: fFieldStart = result.length();
0771:
0772: }
0773: result
0774: .append((i < digitList.count) ? (char) (digitList.digits[i] + zeroDelta)
0775: : zero);
0776: }
0777:
0778: // Record field information
0779: if (iFieldEnd == -1) {
0780: iFieldEnd = result.length();
0781: }
0782: delegate.formatted(INTEGER_FIELD, Field.INTEGER,
0783: Field.INTEGER, iFieldStart, iFieldEnd, result);
0784: if (addedDecimalSeparator) {
0785: delegate.formatted(Field.DECIMAL_SEPARATOR,
0786: Field.DECIMAL_SEPARATOR, iFieldEnd,
0787: fFieldStart, result);
0788: }
0789: if (fFieldStart == -1) {
0790: fFieldStart = result.length();
0791: }
0792: delegate.formatted(FRACTION_FIELD, Field.FRACTION,
0793: Field.FRACTION, fFieldStart, result.length(),
0794: result);
0795:
0796: // The exponent is output using the pattern-specified minimum
0797: // exponent digits. There is no maximum limit to the exponent
0798: // digits, since truncating the exponent would result in an
0799: // unacceptable inaccuracy.
0800: fieldStart = result.length();
0801:
0802: result.append(symbols.getExponentialSymbol());
0803:
0804: delegate.formatted(Field.EXPONENT_SYMBOL,
0805: Field.EXPONENT_SYMBOL, fieldStart, result.length(),
0806: result);
0807:
0808: // For zero values, we force the exponent to zero. We
0809: // must do this here, and not earlier, because the value
0810: // is used to determine integer digit count above.
0811: if (digitList.isZero())
0812: exponent = 0;
0813:
0814: boolean negativeExponent = exponent < 0;
0815: if (negativeExponent) {
0816: exponent = -exponent;
0817: append(result, negativePrefix, delegate,
0818: getNegativePrefixFieldPositions(),
0819: Field.EXPONENT_SIGN);
0820: } else {
0821: append(result, positivePrefix, delegate,
0822: getPositivePrefixFieldPositions(),
0823: Field.EXPONENT_SIGN);
0824: }
0825: digitList.set(exponent);
0826:
0827: int eFieldStart = result.length();
0828:
0829: for (int i = digitList.decimalAt; i < minExponentDigits; ++i)
0830: result.append(zero);
0831: for (int i = 0; i < digitList.decimalAt; ++i) {
0832: result
0833: .append((i < digitList.count) ? (char) (digitList.digits[i] + zeroDelta)
0834: : zero);
0835: }
0836: delegate.formatted(Field.EXPONENT, Field.EXPONENT,
0837: eFieldStart, result.length(), result);
0838: fieldStart = result.length();
0839: if (negativeExponent) {
0840: append(result, negativeSuffix, delegate,
0841: getNegativeSuffixFieldPositions(),
0842: Field.EXPONENT_SIGN);
0843: } else {
0844: append(result, positiveSuffix, delegate,
0845: getPositiveSuffixFieldPositions(),
0846: Field.EXPONENT_SIGN);
0847: }
0848: } else {
0849: int iFieldStart = result.length();
0850:
0851: // Output the integer portion. Here 'count' is the total
0852: // number of integer digits we will display, including both
0853: // leading zeros required to satisfy getMinimumIntegerDigits,
0854: // and actual digits present in the number.
0855: int count = getMinimumIntegerDigits();
0856: int digitIndex = 0; // Index into digitList.fDigits[]
0857: if (digitList.decimalAt > 0 && count < digitList.decimalAt)
0858: count = digitList.decimalAt;
0859:
0860: // Handle the case where getMaximumIntegerDigits() is smaller
0861: // than the real number of integer digits. If this is so, we
0862: // output the least significant max integer digits. For example,
0863: // the value 1997 printed with 2 max integer digits is just "97".
0864:
0865: if (count > getMaximumIntegerDigits()) {
0866: count = getMaximumIntegerDigits();
0867: digitIndex = digitList.decimalAt - count;
0868: }
0869:
0870: int sizeBeforeIntegerPart = result.length();
0871: for (int i = count - 1; i >= 0; --i) {
0872: if (i < digitList.decimalAt
0873: && digitIndex < digitList.count) {
0874: // Output a real digit
0875: result
0876: .append((char) (digitList.digits[digitIndex++] + zeroDelta));
0877: } else {
0878: // Output a leading zero
0879: result.append(zero);
0880: }
0881:
0882: // Output grouping separator if necessary. Don't output a
0883: // grouping separator if i==0 though; that's at the end of
0884: // the integer part.
0885: if (isGroupingUsed() && i > 0 && (groupingSize != 0)
0886: && (i % groupingSize == 0)) {
0887: int gStart = result.length();
0888: result.append(grouping);
0889: delegate.formatted(Field.GROUPING_SEPARATOR,
0890: Field.GROUPING_SEPARATOR, gStart, result
0891: .length(), result);
0892: }
0893: }
0894:
0895: // Determine whether or not there are any printable fractional
0896: // digits. If we've used up the digits we know there aren't.
0897: boolean fractionPresent = (getMinimumFractionDigits() > 0)
0898: || (!isInteger && digitIndex < digitList.count);
0899:
0900: // If there is no fraction present, and we haven't printed any
0901: // integer digits, then print a zero. Otherwise we won't print
0902: // _any_ digits, and we won't be able to parse this string.
0903: if (!fractionPresent
0904: && result.length() == sizeBeforeIntegerPart) {
0905: result.append(zero);
0906: }
0907:
0908: delegate
0909: .formatted(INTEGER_FIELD, Field.INTEGER,
0910: Field.INTEGER, iFieldStart,
0911: result.length(), result);
0912:
0913: // Output the decimal separator if we always do so.
0914: int sStart = result.length();
0915: if (decimalSeparatorAlwaysShown || fractionPresent)
0916: result.append(decimal);
0917:
0918: if (sStart != result.length()) {
0919: delegate.formatted(Field.DECIMAL_SEPARATOR,
0920: Field.DECIMAL_SEPARATOR, sStart, result
0921: .length(), result);
0922: }
0923: int fFieldStart = result.length();
0924:
0925: for (int i = 0; i < getMaximumFractionDigits(); ++i) {
0926: // Here is where we escape from the loop. We escape if we've output
0927: // the maximum fraction digits (specified in the for expression above).
0928: // We also stop when we've output the minimum digits and either:
0929: // we have an integer, so there is no fractional stuff to display,
0930: // or we're out of significant digits.
0931: if (i >= getMinimumFractionDigits()
0932: && (isInteger || digitIndex >= digitList.count))
0933: break;
0934:
0935: // Output leading fractional zeros. These are zeros that come after
0936: // the decimal but before any significant digits. These are only
0937: // output if abs(number being formatted) < 1.0.
0938: if (-1 - i > (digitList.decimalAt - 1)) {
0939: result.append(zero);
0940: continue;
0941: }
0942:
0943: // Output a digit, if we have any precision left, or a
0944: // zero if we don't. We don't want to output noise digits.
0945: if (!isInteger && digitIndex < digitList.count) {
0946: result
0947: .append((char) (digitList.digits[digitIndex++] + zeroDelta));
0948: } else {
0949: result.append(zero);
0950: }
0951: }
0952:
0953: // Record field information for caller.
0954: delegate.formatted(FRACTION_FIELD, Field.FRACTION,
0955: Field.FRACTION, fFieldStart, result.length(),
0956: result);
0957: }
0958:
0959: if (isNegative) {
0960: append(result, negativeSuffix, delegate,
0961: getNegativeSuffixFieldPositions(), Field.SIGN);
0962: } else {
0963: append(result, positiveSuffix, delegate,
0964: getPositiveSuffixFieldPositions(), Field.SIGN);
0965: }
0966:
0967: return result;
0968: }
0969:
0970: /**
0971: * Appends the String <code>string</code> to <code>result</code>.
0972: * <code>delegate</code> is notified of all the
0973: * <code>FieldPosition</code>s in <code>positions</code>.
0974: * <p>
0975: * If one of the <code>FieldPosition</code>s in <code>positions</code>
0976: * identifies a <code>SIGN</code> attribute, it is mapped to
0977: * <code>signAttribute</code>. This is used
0978: * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
0979: * attribute as necessary.
0980: * <p>
0981: * This is used by <code>subformat</code> to add the prefix/suffix.
0982: */
0983: private void append(StringBuffer result, String string,
0984: FieldDelegate delegate, FieldPosition[] positions,
0985: Format.Field signAttribute) {
0986: int start = result.length();
0987:
0988: if (string.length() > 0) {
0989: result.append(string);
0990: for (int counter = 0, max = positions.length; counter < max; counter++) {
0991: FieldPosition fp = positions[counter];
0992: Format.Field attribute = fp.getFieldAttribute();
0993:
0994: if (attribute == Field.SIGN) {
0995: attribute = signAttribute;
0996: }
0997: delegate.formatted(attribute, attribute, start
0998: + fp.getBeginIndex(), start + fp.getEndIndex(),
0999: result);
1000: }
1001: }
1002: }
1003:
1004: /**
1005: * Parses text from a string to produce a <code>Number</code>.
1006: * <p>
1007: * The method attempts to parse text starting at the index given by
1008: * <code>pos</code>.
1009: * If parsing succeeds, then the index of <code>pos</code> is updated
1010: * to the index after the last character used (parsing does not necessarily
1011: * use all characters up to the end of the string), and the parsed
1012: * number is returned. The updated <code>pos</code> can be used to
1013: * indicate the starting point for the next call to this method.
1014: * If an error occurs, then the index of <code>pos</code> is not
1015: * changed, the error index of <code>pos</code> is set to the index of
1016: * the character where the error occurred, and null is returned.
1017: * <p>
1018: * The most economical subclass that can represent the number given by the
1019: * string is chosen. Most integer values are returned as <code>Long</code>
1020: * objects, no matter how they are written: <code>"17"</code> and
1021: * <code>"17.000"</code> both parse to <code>Long(17)</code>. Values that
1022: * cannot fit into a <code>Long</code> are returned as
1023: * <code>Double</code>s. This includes values with a fractional part,
1024: * infinite values, <code>NaN</code>, and the value -0.0.
1025: * <code>DecimalFormat</code> does <em>not</em> decide whether to return
1026: * a <code>Double</code> or a <code>Long</code> based on the presence of a
1027: * decimal separator in the source string. Doing so would prevent integers
1028: * that overflow the mantissa of a double, such as
1029: * <code>"10,000,000,000,000,000.00"</code>, from being parsed accurately.
1030: * Currently, the only classes that <code>parse</code> returns are
1031: * <code>Long</code> and <code>Double</code>, but callers should not rely
1032: * on this. Callers may use the <code>Number</code> methods
1033: * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain the
1034: * type they want.
1035: * <p>
1036: * <code>DecimalFormat</code> parses all Unicode characters that represent
1037: * decimal digits, as defined by <code>Character.digit()</code>. In
1038: * addition, <code>DecimalFormat</code> also recognizes as digits the ten
1039: * consecutive characters starting with the localized zero digit defined in
1040: * the <code>DecimalFormatSymbols</code> object.
1041: *
1042: * @param text the string to be parsed
1043: * @param pos A <code>ParsePosition</code> object with index and error
1044: * index information as described above.
1045: * @return the parsed value, or <code>null</code> if the parse fails
1046: * @exception NullPointerException if <code>text</code> or
1047: * <code>pos</code> is null.
1048: */
1049: public Number parse(String text, ParsePosition pos) {
1050: // special case NaN
1051: if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols
1052: .getNaN().length())) {
1053: pos.index = pos.index + symbols.getNaN().length();
1054: return new Double(Double.NaN);
1055: }
1056:
1057: boolean[] status = new boolean[STATUS_LENGTH];
1058:
1059: if (!subparse(text, pos, digitList, false, status))
1060: return null;
1061:
1062: double doubleResult = 0.0;
1063: long longResult = 0;
1064: boolean gotDouble = true;
1065:
1066: // Finally, have DigitList parse the digits into a value.
1067: if (status[STATUS_INFINITE]) {
1068: doubleResult = Double.POSITIVE_INFINITY;
1069: } else if (digitList.fitsIntoLong(status[STATUS_POSITIVE],
1070: isParseIntegerOnly())) {
1071: gotDouble = false;
1072: longResult = digitList.getLong();
1073: } else
1074: doubleResult = digitList.getDouble();
1075:
1076: // Divide by multiplier. We have to be careful here not to do unneeded
1077: // conversions between double and long.
1078: if (multiplier != 1) {
1079: if (gotDouble)
1080: doubleResult /= multiplier;
1081: else {
1082: // Avoid converting to double if we can
1083: if (longResult % multiplier == 0) {
1084: longResult /= multiplier;
1085: } else {
1086: doubleResult = ((double) longResult) / multiplier;
1087: if (doubleResult < 0)
1088: doubleResult = -doubleResult;
1089: gotDouble = true;
1090: }
1091: }
1092: }
1093:
1094: if (!status[STATUS_POSITIVE]) {
1095: doubleResult = -doubleResult;
1096: // If longResult was Long.MIN_VALUE or a divisor of it (if
1097: // multiplier != 1) then don't negate it.
1098: if (longResult > 0) {
1099: longResult = -longResult;
1100: }
1101: }
1102:
1103: // At this point, if we divided the result by the multiplier, the result may
1104: // fit into a long. We check for this case and return a long if possible.
1105: // We must do this AFTER applying the negative (if appropriate) in order to
1106: // handle the case of LONG_MIN; otherwise, if we do this with a positive value
1107: // -LONG_MIN, the double is > 0, but the long is < 0. This is a C++-specific
1108: // situation. We also must retain a double in the case of -0.0, which will
1109: // compare as == to a long 0 cast to a double (bug 4162852).
1110: if (multiplier != 1 && gotDouble) {
1111: longResult = (long) doubleResult;
1112: gotDouble = (doubleResult != (double) longResult)
1113: || (doubleResult == 0.0 && !status[STATUS_POSITIVE] && !isParseIntegerOnly());
1114: }
1115:
1116: return gotDouble ? (Number) new Double(doubleResult)
1117: : (Number) new Long(longResult);
1118: }
1119:
1120: private static final int STATUS_INFINITE = 0;
1121: private static final int STATUS_POSITIVE = 1;
1122: private static final int STATUS_LENGTH = 2;
1123:
1124: /**
1125: * Parse the given text into a number. The text is parsed beginning at
1126: * parsePosition, until an unparseable character is seen.
1127: * @param text The string to parse.
1128: * @param parsePosition The position at which to being parsing. Upon
1129: * return, the first unparseable character.
1130: * @param digits The DigitList to set to the parsed value.
1131: * @param isExponent If true, parse an exponent. This means no
1132: * infinite values and integer only.
1133: * @param status Upon return contains boolean status flags indicating
1134: * whether the value was infinite and whether it was positive.
1135: */
1136: private final boolean subparse(String text,
1137: ParsePosition parsePosition, DigitList digits,
1138: boolean isExponent, boolean status[]) {
1139: int position = parsePosition.index;
1140: int oldStart = parsePosition.index;
1141: int backup;
1142:
1143: // check for positivePrefix; take longest
1144: boolean gotPositive = text.regionMatches(position,
1145: positivePrefix, 0, positivePrefix.length());
1146: boolean gotNegative = text.regionMatches(position,
1147: negativePrefix, 0, negativePrefix.length());
1148: if (gotPositive && gotNegative) {
1149: if (positivePrefix.length() > negativePrefix.length())
1150: gotNegative = false;
1151: else if (positivePrefix.length() < negativePrefix.length())
1152: gotPositive = false;
1153: }
1154: if (gotPositive) {
1155: position += positivePrefix.length();
1156: } else if (gotNegative) {
1157: position += negativePrefix.length();
1158: } else {
1159: parsePosition.errorIndex = position;
1160: return false;
1161: }
1162: // process digits or Inf, find decimal position
1163: status[STATUS_INFINITE] = false;
1164: if (!isExponent
1165: && text.regionMatches(position, symbols.getInfinity(),
1166: 0, symbols.getInfinity().length())) {
1167: position += symbols.getInfinity().length();
1168: status[STATUS_INFINITE] = true;
1169: } else {
1170: // We now have a string of digits, possibly with grouping symbols,
1171: // and decimal points. We want to process these into a DigitList.
1172: // We don't want to put a bunch of leading zeros into the DigitList
1173: // though, so we keep track of the location of the decimal point,
1174: // put only significant digits into the DigitList, and adjust the
1175: // exponent as needed.
1176:
1177: digits.decimalAt = digits.count = 0;
1178: char zero = symbols.getZeroDigit();
1179: char decimal = isCurrencyFormat ? symbols
1180: .getMonetaryDecimalSeparator() : symbols
1181: .getDecimalSeparator();
1182: char grouping = symbols.getGroupingSeparator();
1183: char exponentChar = symbols.getExponentialSymbol();
1184: boolean sawDecimal = false;
1185: boolean sawExponent = false;
1186: boolean sawDigit = false;
1187: int exponent = 0; // Set to the exponent value, if any
1188:
1189: // We have to track digitCount ourselves, because digits.count will
1190: // pin when the maximum allowable digits is reached.
1191: int digitCount = 0;
1192:
1193: backup = -1;
1194: for (; position < text.length(); ++position) {
1195: char ch = text.charAt(position);
1196:
1197: /* We recognize all digit ranges, not only the Latin digit range
1198: * '0'..'9'. We do so by using the Character.digit() method,
1199: * which converts a valid Unicode digit to the range 0..9.
1200: *
1201: * The character 'ch' may be a digit. If so, place its value
1202: * from 0 to 9 in 'digit'. First try using the locale digit,
1203: * which may or MAY NOT be a standard Unicode digit range. If
1204: * this fails, try using the standard Unicode digit ranges by
1205: * calling Character.digit(). If this also fails, digit will
1206: * have a value outside the range 0..9.
1207: */
1208: int digit = ch - zero;
1209: if (digit < 0 || digit > 9)
1210: digit = Character.digit(ch, 10);
1211:
1212: if (digit == 0) {
1213: // Cancel out backup setting (see grouping handler below)
1214: backup = -1; // Do this BEFORE continue statement below!!!
1215: sawDigit = true;
1216:
1217: // Handle leading zeros
1218: if (digits.count == 0) {
1219: // Ignore leading zeros in integer part of number.
1220: if (!sawDecimal)
1221: continue;
1222:
1223: // If we have seen the decimal, but no significant digits yet,
1224: // then we account for leading zeros by decrementing the
1225: // digits.decimalAt into negative values.
1226: --digits.decimalAt;
1227: } else {
1228: ++digitCount;
1229: digits.append((char) (digit + '0'));
1230: }
1231: } else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above
1232: {
1233: sawDigit = true;
1234: ++digitCount;
1235: digits.append((char) (digit + '0'));
1236:
1237: // Cancel out backup setting (see grouping handler below)
1238: backup = -1;
1239: } else if (!isExponent && ch == decimal) {
1240: // If we're only parsing integers, or if we ALREADY saw the
1241: // decimal, then don't parse this one.
1242: if (isParseIntegerOnly() || sawDecimal)
1243: break;
1244: digits.decimalAt = digitCount; // Not digits.count!
1245: sawDecimal = true;
1246: } else if (!isExponent && ch == grouping
1247: && isGroupingUsed()) {
1248: if (sawDecimal) {
1249: break;
1250: }
1251: // Ignore grouping characters, if we are using them, but require
1252: // that they be followed by a digit. Otherwise we backup and
1253: // reprocess them.
1254: backup = position;
1255: } else if (!isExponent && ch == exponentChar
1256: && !sawExponent) {
1257: // Process the exponent by recursively calling this method.
1258: ParsePosition pos = new ParsePosition(position + 1);
1259: boolean[] stat = new boolean[STATUS_LENGTH];
1260: DigitList exponentDigits = new DigitList();
1261:
1262: if (subparse(text, pos, exponentDigits, true, stat)
1263: && exponentDigits.fitsIntoLong(
1264: stat[STATUS_POSITIVE], true)) {
1265: position = pos.index; // Advance past the exponent
1266: exponent = (int) exponentDigits.getLong();
1267: if (!stat[STATUS_POSITIVE])
1268: exponent = -exponent;
1269: sawExponent = true;
1270: }
1271: break; // Whether we fail or succeed, we exit this loop
1272: } else
1273: break;
1274: }
1275:
1276: if (backup != -1)
1277: position = backup;
1278:
1279: // If there was no decimal point we have an integer
1280: if (!sawDecimal)
1281: digits.decimalAt = digitCount; // Not digits.count!
1282:
1283: // Adjust for exponent, if any
1284: digits.decimalAt += exponent;
1285:
1286: // If none of the text string was recognized. For example, parse
1287: // "x" with pattern "#0.00" (return index and error index both 0)
1288: // parse "$" with pattern "$#0.00". (return index 0 and error index
1289: // 1).
1290: if (!sawDigit && digitCount == 0) {
1291: parsePosition.index = oldStart;
1292: parsePosition.errorIndex = oldStart;
1293: return false;
1294: }
1295: }
1296:
1297: // check for positiveSuffix
1298: if (gotPositive)
1299: gotPositive = text.regionMatches(position, positiveSuffix,
1300: 0, positiveSuffix.length());
1301: if (gotNegative)
1302: gotNegative = text.regionMatches(position, negativeSuffix,
1303: 0, negativeSuffix.length());
1304:
1305: // if both match, take longest
1306: if (gotPositive && gotNegative) {
1307: if (positiveSuffix.length() > negativeSuffix.length())
1308: gotNegative = false;
1309: else if (positiveSuffix.length() < negativeSuffix.length())
1310: gotPositive = false;
1311: }
1312:
1313: // fail if neither or both
1314: if (gotPositive == gotNegative) {
1315: parsePosition.errorIndex = position;
1316: return false;
1317: }
1318:
1319: parsePosition.index = position
1320: + (gotPositive ? positiveSuffix.length()
1321: : negativeSuffix.length()); // mark success!
1322:
1323: status[STATUS_POSITIVE] = gotPositive;
1324: if (parsePosition.index == oldStart) {
1325: parsePosition.errorIndex = position;
1326: return false;
1327: }
1328: return true;
1329: }
1330:
1331: /**
1332: * Returns the decimal format symbols, which is generally not changed
1333: * by the programmer or user.
1334: * @return desired DecimalFormatSymbols
1335: * @see java.text.DecimalFormatSymbols
1336: */
1337: public DecimalFormatSymbols getDecimalFormatSymbols() {
1338: try {
1339: // don't allow multiple references
1340: return (DecimalFormatSymbols) symbols.clone();
1341: } catch (Exception foo) {
1342: return null; // should never happen
1343: }
1344: }
1345:
1346: /**
1347: * Sets the decimal format symbols, which is generally not changed
1348: * by the programmer or user.
1349: * @param newSymbols desired DecimalFormatSymbols
1350: * @see java.text.DecimalFormatSymbols
1351: */
1352: public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
1353: try {
1354: // don't allow multiple references
1355: symbols = (DecimalFormatSymbols) newSymbols.clone();
1356: expandAffixes();
1357: } catch (Exception foo) {
1358: // should never happen
1359: }
1360: }
1361:
1362: /**
1363: * Get the positive prefix.
1364: * <P>Examples: +123, $123, sFr123
1365: */
1366: public String getPositivePrefix() {
1367: return positivePrefix;
1368: }
1369:
1370: /**
1371: * Set the positive prefix.
1372: * <P>Examples: +123, $123, sFr123
1373: */
1374: public void setPositivePrefix(String newValue) {
1375: positivePrefix = newValue;
1376: posPrefixPattern = null;
1377: positivePrefixFieldPositions = null;
1378: }
1379:
1380: /**
1381: * Returns the FieldPositions of the fields in the prefix used for
1382: * positive numbers. This is not used if the user has explicitly set
1383: * a positive prefix via <code>setPositivePrefix</code>. This is
1384: * lazily created.
1385: *
1386: * @return FieldPositions in positive prefix
1387: */
1388: private FieldPosition[] getPositivePrefixFieldPositions() {
1389: if (positivePrefixFieldPositions == null) {
1390: if (posPrefixPattern != null) {
1391: positivePrefixFieldPositions = expandAffix(posPrefixPattern);
1392: } else {
1393: positivePrefixFieldPositions = EmptyFieldPositionArray;
1394: }
1395: }
1396: return positivePrefixFieldPositions;
1397: }
1398:
1399: /**
1400: * Get the negative prefix.
1401: * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1402: */
1403: public String getNegativePrefix() {
1404: return negativePrefix;
1405: }
1406:
1407: /**
1408: * Set the negative prefix.
1409: * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1410: */
1411: public void setNegativePrefix(String newValue) {
1412: negativePrefix = newValue;
1413: negPrefixPattern = null;
1414: }
1415:
1416: /**
1417: * Returns the FieldPositions of the fields in the prefix used for
1418: * negative numbers. This is not used if the user has explicitly set
1419: * a negative prefix via <code>setNegativePrefix</code>. This is
1420: * lazily created.
1421: *
1422: * @return FieldPositions in positive prefix
1423: */
1424: private FieldPosition[] getNegativePrefixFieldPositions() {
1425: if (negativePrefixFieldPositions == null) {
1426: if (negPrefixPattern != null) {
1427: negativePrefixFieldPositions = expandAffix(negPrefixPattern);
1428: } else {
1429: negativePrefixFieldPositions = EmptyFieldPositionArray;
1430: }
1431: }
1432: return negativePrefixFieldPositions;
1433: }
1434:
1435: /**
1436: * Get the positive suffix.
1437: * <P>Example: 123%
1438: */
1439: public String getPositiveSuffix() {
1440: return positiveSuffix;
1441: }
1442:
1443: /**
1444: * Set the positive suffix.
1445: * <P>Example: 123%
1446: */
1447: public void setPositiveSuffix(String newValue) {
1448: positiveSuffix = newValue;
1449: posSuffixPattern = null;
1450: }
1451:
1452: /**
1453: * Returns the FieldPositions of the fields in the suffix used for
1454: * positive numbers. This is not used if the user has explicitly set
1455: * a positive suffix via <code>setPositiveSuffix</code>. This is
1456: * lazily created.
1457: *
1458: * @return FieldPositions in positive prefix
1459: */
1460: private FieldPosition[] getPositiveSuffixFieldPositions() {
1461: if (positiveSuffixFieldPositions == null) {
1462: if (posSuffixPattern != null) {
1463: positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
1464: } else {
1465: positiveSuffixFieldPositions = EmptyFieldPositionArray;
1466: }
1467: }
1468: return positiveSuffixFieldPositions;
1469: }
1470:
1471: /**
1472: * Get the negative suffix.
1473: * <P>Examples: -123%, ($123) (with positive suffixes)
1474: */
1475: public String getNegativeSuffix() {
1476: return negativeSuffix;
1477: }
1478:
1479: /**
1480: * Set the positive suffix.
1481: * <P>Examples: 123%
1482: */
1483: public void setNegativeSuffix(String newValue) {
1484: negativeSuffix = newValue;
1485: negSuffixPattern = null;
1486: }
1487:
1488: /**
1489: * Returns the FieldPositions of the fields in the suffix used for
1490: * negative numbers. This is not used if the user has explicitly set
1491: * a negative suffix via <code>setNegativeSuffix</code>. This is
1492: * lazily created.
1493: *
1494: * @return FieldPositions in positive prefix
1495: */
1496: private FieldPosition[] getNegativeSuffixFieldPositions() {
1497: if (negativeSuffixFieldPositions == null) {
1498: if (negSuffixPattern != null) {
1499: negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
1500: } else {
1501: negativeSuffixFieldPositions = EmptyFieldPositionArray;
1502: }
1503: }
1504: return negativeSuffixFieldPositions;
1505: }
1506:
1507: /**
1508: * Get the multiplier for use in percent, permill, etc.
1509: * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
1510: * (For Arabic, use arabic percent symbol).
1511: * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
1512: * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
1513: */
1514: public int getMultiplier() {
1515: return multiplier;
1516: }
1517:
1518: /**
1519: * Set the multiplier for use in percent, permill, etc.
1520: * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
1521: * (For Arabic, use arabic percent symbol).
1522: * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
1523: * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
1524: */
1525: public void setMultiplier(int newValue) {
1526: multiplier = newValue;
1527: }
1528:
1529: /**
1530: * Return the grouping size. Grouping size is the number of digits between
1531: * grouping separators in the integer portion of a number. For example,
1532: * in the number "123,456.78", the grouping size is 3.
1533: * @see #setGroupingSize
1534: * @see java.text.NumberFormat#isGroupingUsed
1535: * @see java.text.DecimalFormatSymbols#getGroupingSeparator
1536: */
1537: public int getGroupingSize() {
1538: return groupingSize;
1539: }
1540:
1541: /**
1542: * Set the grouping size. Grouping size is the number of digits between
1543: * grouping separators in the integer portion of a number. For example,
1544: * in the number "123,456.78", the grouping size is 3.
1545: * @see #getGroupingSize
1546: * @see java.text.NumberFormat#setGroupingUsed
1547: * @see java.text.DecimalFormatSymbols#setGroupingSeparator
1548: */
1549: public void setGroupingSize(int newValue) {
1550: groupingSize = (byte) newValue;
1551: }
1552:
1553: /**
1554: * Allows you to get the behavior of the decimal separator with integers.
1555: * (The decimal separator will always appear with decimals.)
1556: * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1557: */
1558: public boolean isDecimalSeparatorAlwaysShown() {
1559: return decimalSeparatorAlwaysShown;
1560: }
1561:
1562: /**
1563: * Allows you to set the behavior of the decimal separator with integers.
1564: * (The decimal separator will always appear with decimals.)
1565: * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1566: */
1567: public void setDecimalSeparatorAlwaysShown(boolean newValue) {
1568: decimalSeparatorAlwaysShown = newValue;
1569: }
1570:
1571: /**
1572: * Standard override; no change in semantics.
1573: */
1574: public Object clone() {
1575: try {
1576: DecimalFormat other = (DecimalFormat) super .clone();
1577: other.symbols = (DecimalFormatSymbols) symbols.clone();
1578: other.digitList = (DigitList) digitList.clone();
1579: return other;
1580: } catch (Exception e) {
1581: throw new InternalError();
1582: }
1583: }
1584:
1585: /**
1586: * Overrides equals
1587: */
1588: public boolean equals(Object obj) {
1589: if (obj == null)
1590: return false;
1591: if (!super .equals(obj))
1592: return false; // super does class check
1593: DecimalFormat other = (DecimalFormat) obj;
1594: return ((posPrefixPattern == other.posPrefixPattern && positivePrefix
1595: .equals(other.positivePrefix)) || (posPrefixPattern != null && posPrefixPattern
1596: .equals(other.posPrefixPattern)))
1597: && ((posSuffixPattern == other.posSuffixPattern && positiveSuffix
1598: .equals(other.positiveSuffix)) || (posSuffixPattern != null && posSuffixPattern
1599: .equals(other.posSuffixPattern)))
1600: && ((negPrefixPattern == other.negPrefixPattern && negativePrefix
1601: .equals(other.negativePrefix)) || (negPrefixPattern != null && negPrefixPattern
1602: .equals(other.negPrefixPattern)))
1603: && ((negSuffixPattern == other.negSuffixPattern && negativeSuffix
1604: .equals(other.negativeSuffix)) || (negSuffixPattern != null && negSuffixPattern
1605: .equals(other.negSuffixPattern)))
1606: && multiplier == other.multiplier
1607: && groupingSize == other.groupingSize
1608: && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
1609: && useExponentialNotation == other.useExponentialNotation
1610: && (!useExponentialNotation || minExponentDigits == other.minExponentDigits)
1611: && symbols.equals(other.symbols);
1612: }
1613:
1614: /**
1615: * Overrides hashCode
1616: */
1617: public int hashCode() {
1618: return super .hashCode() * 37 + positivePrefix.hashCode();
1619: // just enough fields for a reasonable distribution
1620: }
1621:
1622: /**
1623: * Synthesizes a pattern string that represents the current state
1624: * of this Format object.
1625: * @see #applyPattern
1626: */
1627: public String toPattern() {
1628: return toPattern(false);
1629: }
1630:
1631: /**
1632: * Synthesizes a localized pattern string that represents the current
1633: * state of this Format object.
1634: * @see #applyPattern
1635: */
1636: public String toLocalizedPattern() {
1637: return toPattern(true);
1638: }
1639:
1640: /**
1641: * Expand the affix pattern strings into the expanded affix strings. If any
1642: * affix pattern string is null, do not expand it. This method should be
1643: * called any time the symbols or the affix patterns change in order to keep
1644: * the expanded affix strings up to date.
1645: */
1646: private void expandAffixes() {
1647: // Reuse one StringBuffer for better performance
1648: StringBuffer buffer = new StringBuffer();
1649: if (posPrefixPattern != null) {
1650: positivePrefix = expandAffix(posPrefixPattern, buffer);
1651: positivePrefixFieldPositions = null;
1652: }
1653: if (posSuffixPattern != null) {
1654: positiveSuffix = expandAffix(posSuffixPattern, buffer);
1655: positiveSuffixFieldPositions = null;
1656: }
1657: if (negPrefixPattern != null) {
1658: negativePrefix = expandAffix(negPrefixPattern, buffer);
1659: negativePrefixFieldPositions = null;
1660: }
1661: if (negSuffixPattern != null) {
1662: negativeSuffix = expandAffix(negSuffixPattern, buffer);
1663: negativeSuffixFieldPositions = null;
1664: }
1665: }
1666:
1667: /**
1668: * Expand an affix pattern into an affix string. All characters in the
1669: * pattern are literal unless prefixed by QUOTE. The following characters
1670: * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
1671: * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
1672: * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
1673: * currency code. Any other character after a QUOTE represents itself.
1674: * QUOTE must be followed by another character; QUOTE may not occur by
1675: * itself at the end of the pattern.
1676: *
1677: * @param pattern the non-null, possibly empty pattern
1678: * @param buffer a scratch StringBuffer; its contents will be lost
1679: * @return the expanded equivalent of pattern
1680: */
1681: private String expandAffix(String pattern, StringBuffer buffer) {
1682: buffer.setLength(0);
1683: for (int i = 0; i < pattern.length();) {
1684: char c = pattern.charAt(i++);
1685: if (c == QUOTE) {
1686: c = pattern.charAt(i++);
1687: switch (c) {
1688: case CURRENCY_SIGN:
1689: if (i < pattern.length()
1690: && pattern.charAt(i) == CURRENCY_SIGN) {
1691: ++i;
1692: buffer.append(symbols
1693: .getInternationalCurrencySymbol());
1694: } else {
1695: buffer.append(symbols.getCurrencySymbol());
1696: }
1697: continue;
1698: case PATTERN_PERCENT:
1699: c = symbols.getPercent();
1700: break;
1701: case PATTERN_PER_MILLE:
1702: c = symbols.getPerMill();
1703: break;
1704: case PATTERN_MINUS:
1705: c = symbols.getMinusSign();
1706: break;
1707: }
1708: }
1709: buffer.append(c);
1710: }
1711: return buffer.toString();
1712: }
1713:
1714: /**
1715: * Expand an affix pattern into an array of FieldPositions describing
1716: * how the pattern would be expanded.
1717: * All characters in the
1718: * pattern are literal unless prefixed by QUOTE. The following characters
1719: * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
1720: * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
1721: * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
1722: * currency code. Any other character after a QUOTE represents itself.
1723: * QUOTE must be followed by another character; QUOTE may not occur by
1724: * itself at the end of the pattern.
1725: *
1726: * @param pattern the non-null, possibly empty pattern
1727: * @return FieldPosition array of the resulting fields.
1728: */
1729: private FieldPosition[] expandAffix(String pattern) {
1730: ArrayList positions = null;
1731: int stringIndex = 0;
1732: for (int i = 0; i < pattern.length();) {
1733: char c = pattern.charAt(i++);
1734: if (c == QUOTE) {
1735: int field = -1;
1736: Format.Field fieldID = null;
1737: c = pattern.charAt(i++);
1738: switch (c) {
1739: case CURRENCY_SIGN:
1740: String string;
1741: if (i < pattern.length()
1742: && pattern.charAt(i) == CURRENCY_SIGN) {
1743: ++i;
1744: string = symbols
1745: .getInternationalCurrencySymbol();
1746: } else {
1747: string = symbols.getCurrencySymbol();
1748: }
1749: if (string.length() > 0) {
1750: if (positions == null) {
1751: positions = new ArrayList(2);
1752: }
1753: FieldPosition fp = new FieldPosition(
1754: Field.CURRENCY);
1755: fp.setBeginIndex(stringIndex);
1756: fp.setEndIndex(stringIndex + string.length());
1757: positions.add(fp);
1758: stringIndex += string.length();
1759: }
1760: continue;
1761: case PATTERN_PERCENT:
1762: c = symbols.getPercent();
1763: field = -1;
1764: fieldID = Field.PERCENT;
1765: break;
1766: case PATTERN_PER_MILLE:
1767: c = symbols.getPerMill();
1768: field = -1;
1769: fieldID = Field.PERMILLE;
1770: break;
1771: case PATTERN_MINUS:
1772: c = symbols.getMinusSign();
1773: field = -1;
1774: fieldID = Field.SIGN;
1775: break;
1776: }
1777: if (fieldID != null) {
1778: if (positions == null) {
1779: positions = new ArrayList(2);
1780: }
1781: FieldPosition fp = new FieldPosition(fieldID, field);
1782: fp.setBeginIndex(stringIndex);
1783: fp.setEndIndex(stringIndex + 1);
1784: positions.add(fp);
1785: }
1786: }
1787: stringIndex++;
1788: }
1789: if (positions != null) {
1790: return (FieldPosition[]) positions
1791: .toArray(EmptyFieldPositionArray);
1792: }
1793: return EmptyFieldPositionArray;
1794: }
1795:
1796: /**
1797: * Appends an affix pattern to the given StringBuffer, quoting special
1798: * characters as needed. Uses the internal affix pattern, if that exists,
1799: * or the literal affix, if the internal affix pattern is null. The
1800: * appended string will generate the same affix pattern (or literal affix)
1801: * when passed to toPattern().
1802: *
1803: * @param buffer the affix string is appended to this
1804: * @param affixPattern a pattern such as posPrefixPattern; may be null
1805: * @param expAffix a corresponding expanded affix, such as positivePrefix.
1806: * Ignored unless affixPattern is null. If affixPattern is null, then
1807: * expAffix is appended as a literal affix.
1808: * @param localized true if the appended pattern should contain localized
1809: * pattern characters; otherwise, non-localized pattern chars are appended
1810: */
1811: private void appendAffix(StringBuffer buffer, String affixPattern,
1812: String expAffix, boolean localized) {
1813: if (affixPattern == null) {
1814: appendAffix(buffer, expAffix, localized);
1815: } else {
1816: int i;
1817: for (int pos = 0; pos < affixPattern.length(); pos = i) {
1818: i = affixPattern.indexOf(QUOTE, pos);
1819: if (i < 0) {
1820: appendAffix(buffer, affixPattern.substring(pos),
1821: localized);
1822: break;
1823: }
1824: if (i > pos) {
1825: appendAffix(buffer, affixPattern.substring(pos, i),
1826: localized);
1827: }
1828: char c = affixPattern.charAt(++i);
1829: ++i;
1830: if (c == QUOTE) {
1831: buffer.append(c);
1832: // Fall through and append another QUOTE below
1833: } else if (c == CURRENCY_SIGN
1834: && i < affixPattern.length()
1835: && affixPattern.charAt(i) == CURRENCY_SIGN) {
1836: ++i;
1837: buffer.append(c);
1838: // Fall through and append another CURRENCY_SIGN below
1839: } else if (localized) {
1840: switch (c) {
1841: case PATTERN_PERCENT:
1842: c = symbols.getPercent();
1843: break;
1844: case PATTERN_PER_MILLE:
1845: c = symbols.getPerMill();
1846: break;
1847: case PATTERN_MINUS:
1848: c = symbols.getMinusSign();
1849: break;
1850: }
1851: }
1852: buffer.append(c);
1853: }
1854: }
1855: }
1856:
1857: /**
1858: * Append an affix to the given StringBuffer, using quotes if
1859: * there are special characters. Single quotes themselves must be
1860: * escaped in either case.
1861: */
1862: private void appendAffix(StringBuffer buffer, String affix,
1863: boolean localized) {
1864: boolean needQuote;
1865: if (localized) {
1866: needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
1867: || affix.indexOf(symbols.getGroupingSeparator()) >= 0
1868: || affix.indexOf(symbols.getDecimalSeparator()) >= 0
1869: || affix.indexOf(symbols.getPercent()) >= 0
1870: || affix.indexOf(symbols.getPerMill()) >= 0
1871: || affix.indexOf(symbols.getDigit()) >= 0
1872: || affix.indexOf(symbols.getPatternSeparator()) >= 0
1873: || affix.indexOf(symbols.getMinusSign()) >= 0
1874: || affix.indexOf(CURRENCY_SIGN) >= 0;
1875: } else {
1876: needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
1877: || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
1878: || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
1879: || affix.indexOf(PATTERN_PERCENT) >= 0
1880: || affix.indexOf(PATTERN_PER_MILLE) >= 0
1881: || affix.indexOf(PATTERN_DIGIT) >= 0
1882: || affix.indexOf(PATTERN_SEPARATOR) >= 0
1883: || affix.indexOf(PATTERN_MINUS) >= 0
1884: || affix.indexOf(CURRENCY_SIGN) >= 0;
1885: }
1886: if (needQuote)
1887: buffer.append('\'');
1888: if (affix.indexOf('\'') < 0)
1889: buffer.append(affix);
1890: else {
1891: for (int j = 0; j < affix.length(); ++j) {
1892: char c = affix.charAt(j);
1893: buffer.append(c);
1894: if (c == '\'')
1895: buffer.append(c);
1896: }
1897: }
1898: if (needQuote)
1899: buffer.append('\'');
1900: }
1901:
1902: /**
1903: * Does the real work of generating a pattern. */
1904: private String toPattern(boolean localized) {
1905: StringBuffer result = new StringBuffer();
1906: for (int j = 1; j >= 0; --j) {
1907: if (j == 1)
1908: appendAffix(result, posPrefixPattern, positivePrefix,
1909: localized);
1910: else
1911: appendAffix(result, negPrefixPattern, negativePrefix,
1912: localized);
1913: int i;
1914: int digitCount = useExponentialNotation ? getMaximumIntegerDigits()
1915: : Math.max(groupingSize, getMinimumIntegerDigits()) + 1;
1916: for (i = digitCount; i > 0; --i) {
1917: if (i != digitCount && isGroupingUsed()
1918: && groupingSize != 0 && i % groupingSize == 0) {
1919: result.append(localized ? symbols
1920: .getGroupingSeparator()
1921: : PATTERN_GROUPING_SEPARATOR);
1922: }
1923: result
1924: .append(i <= getMinimumIntegerDigits() ? (localized ? symbols
1925: .getZeroDigit()
1926: : PATTERN_ZERO_DIGIT)
1927: : (localized ? symbols.getDigit()
1928: : PATTERN_DIGIT));
1929: }
1930: if (getMaximumFractionDigits() > 0
1931: || decimalSeparatorAlwaysShown)
1932: result.append(localized ? symbols.getDecimalSeparator()
1933: : PATTERN_DECIMAL_SEPARATOR);
1934: for (i = 0; i < getMaximumFractionDigits(); ++i) {
1935: if (i < getMinimumFractionDigits()) {
1936: result.append(localized ? symbols.getZeroDigit()
1937: : PATTERN_ZERO_DIGIT);
1938: } else {
1939: result.append(localized ? symbols.getDigit()
1940: : PATTERN_DIGIT);
1941: }
1942: }
1943: if (useExponentialNotation) {
1944: result.append(localized ? symbols
1945: .getExponentialSymbol() : PATTERN_EXPONENT);
1946: for (i = 0; i < minExponentDigits; ++i)
1947: result.append(localized ? symbols.getZeroDigit()
1948: : PATTERN_ZERO_DIGIT);
1949: }
1950: if (j == 1) {
1951: appendAffix(result, posSuffixPattern, positiveSuffix,
1952: localized);
1953: if ((negSuffixPattern == posSuffixPattern && // n == p == null
1954: negativeSuffix.equals(positiveSuffix))
1955: || (negSuffixPattern != null && negSuffixPattern
1956: .equals(posSuffixPattern))) {
1957: if ((negPrefixPattern != null
1958: && posPrefixPattern != null && negPrefixPattern
1959: .equals("'-" + posPrefixPattern))
1960: || (negPrefixPattern == posPrefixPattern && // n == p == null
1961: negativePrefix.equals(symbols
1962: .getMinusSign()
1963: + positivePrefix)))
1964: break;
1965: }
1966: result.append(localized ? symbols.getPatternSeparator()
1967: : PATTERN_SEPARATOR);
1968: } else
1969: appendAffix(result, negSuffixPattern, negativeSuffix,
1970: localized);
1971: }
1972: return result.toString();
1973: }
1974:
1975: /**
1976: * Apply the given pattern to this Format object. A pattern is a
1977: * short-hand specification for the various formatting properties.
1978: * These properties can also be changed individually through the
1979: * various setter methods.
1980: * <p>
1981: * There is no limit to integer digits are set
1982: * by this routine, since that is the typical end-user desire;
1983: * use setMaximumInteger if you want to set a real value.
1984: * For negative numbers, use a second pattern, separated by a semicolon
1985: * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
1986: * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
1987: * a maximum of 2 fraction digits.
1988: * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
1989: * parentheses.
1990: * <p>In negative patterns, the minimum and maximum counts are ignored;
1991: * these are presumed to be set in the positive pattern.
1992: *
1993: * @exception NullPointerException if <code>pattern</code> is null
1994: * @exception IllegalArgumentException if the given pattern is invalid.
1995: */
1996: public void applyPattern(String pattern) {
1997: applyPattern(pattern, false);
1998: }
1999:
2000: /**
2001: * Apply the given pattern to this Format object. The pattern
2002: * is assumed to be in a localized notation. A pattern is a
2003: * short-hand specification for the various formatting properties.
2004: * These properties can also be changed individually through the
2005: * various setter methods.
2006: * <p>
2007: * There is no limit to integer digits are set
2008: * by this routine, since that is the typical end-user desire;
2009: * use setMaximumInteger if you want to set a real value.
2010: * For negative numbers, use a second pattern, separated by a semicolon
2011: * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
2012: * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
2013: * a maximum of 2 fraction digits.
2014: * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
2015: * parentheses.
2016: * <p>In negative patterns, the minimum and maximum counts are ignored;
2017: * these are presumed to be set in the positive pattern.
2018: *
2019: * @exception NullPointerException if <code>pattern</code> is null
2020: * @exception IllegalArgumentException if the given pattern is invalid.
2021: */
2022: public void applyLocalizedPattern(String pattern) {
2023: applyPattern(pattern, true);
2024: }
2025:
2026: /**
2027: * Does the real work of applying a pattern.
2028: */
2029: private void applyPattern(String pattern, boolean localized) {
2030: char zeroDigit = PATTERN_ZERO_DIGIT;
2031: char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
2032: char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
2033: char percent = PATTERN_PERCENT;
2034: char perMill = PATTERN_PER_MILLE;
2035: char digit = PATTERN_DIGIT;
2036: char separator = PATTERN_SEPARATOR;
2037: char exponent = PATTERN_EXPONENT;
2038: char minus = PATTERN_MINUS;
2039: if (localized) {
2040: zeroDigit = symbols.getZeroDigit();
2041: groupingSeparator = symbols.getGroupingSeparator();
2042: decimalSeparator = symbols.getDecimalSeparator();
2043: percent = symbols.getPercent();
2044: perMill = symbols.getPerMill();
2045: digit = symbols.getDigit();
2046: separator = symbols.getPatternSeparator();
2047: exponent = symbols.getExponentialSymbol();
2048: minus = symbols.getMinusSign();
2049: }
2050: boolean gotNegative = false;
2051:
2052: decimalSeparatorAlwaysShown = false;
2053: isCurrencyFormat = false;
2054: useExponentialNotation = false;
2055:
2056: // Two variables are used to record the subrange of the pattern
2057: // occupied by phase 1. This is used during the processing of the
2058: // second pattern (the one representing negative numbers) to ensure
2059: // that no deviation exists in phase 1 between the two patterns.
2060: int phaseOneStart = 0;
2061: int phaseOneLength = 0;
2062: /** Back-out comment : HShih
2063: * boolean phaseTwo = false;
2064: */
2065:
2066: int start = 0;
2067: for (int j = 1; j >= 0 && start < pattern.length(); --j) {
2068: boolean inQuote = false;
2069: StringBuffer prefix = new StringBuffer();
2070: StringBuffer suffix = new StringBuffer();
2071: int decimalPos = -1;
2072: int multiplier = 1;
2073: int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
2074: byte groupingCount = -1;
2075:
2076: // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
2077: // the section of the pattern with digits, decimal separator,
2078: // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
2079: // percent, permille, and currency symbols are recognized and
2080: // translated. The separation of the characters into phases is
2081: // strictly enforced; if phase 1 characters are to appear in the
2082: // suffix, for example, they must be quoted.
2083: int phase = 0;
2084:
2085: // The affix is either the prefix or the suffix.
2086: StringBuffer affix = prefix;
2087:
2088: for (int pos = start; pos < pattern.length(); ++pos) {
2089: char ch = pattern.charAt(pos);
2090: switch (phase) {
2091: case 0:
2092: case 2:
2093: // Process the prefix / suffix characters
2094: if (inQuote) {
2095: // A quote within quotes indicates either the closing
2096: // quote or two quotes, which is a quote literal. That is,
2097: // we have the second quote in 'do' or 'don''t'.
2098: if (ch == QUOTE) {
2099: if ((pos + 1) < pattern.length()
2100: && pattern.charAt(pos + 1) == QUOTE) {
2101: ++pos;
2102: affix.append("''"); // 'don''t'
2103: } else {
2104: inQuote = false; // 'do'
2105: }
2106: continue;
2107: }
2108: } else {
2109: // Process unquoted characters seen in prefix or suffix
2110: // phase.
2111: if (ch == digit || ch == zeroDigit
2112: || ch == groupingSeparator
2113: || ch == decimalSeparator) {
2114: // Any of these characters implicitly begins the next
2115: // phase. If we are in phase 2, there is no next phase,
2116: // so these characters are illegal.
2117: /**
2118: * 1.2 Back-out comment : HShih
2119: * Can't throw exception here.
2120: * if (phase == 2)
2121: * throw new IllegalArgumentException("Unquoted special character '" +
2122: * ch + "' in pattern \"" +
2123: * pattern + '"');
2124: */
2125: phase = 1;
2126: if (j == 1)
2127: phaseOneStart = pos;
2128: --pos; // Reprocess this character
2129: continue;
2130: } else if (ch == CURRENCY_SIGN) {
2131: // Use lookahead to determine if the currency sign is
2132: // doubled or not.
2133: boolean doubled = (pos + 1) < pattern
2134: .length()
2135: && pattern.charAt(pos + 1) == CURRENCY_SIGN;
2136: if (doubled)
2137: ++pos; // Skip over the doubled character
2138: isCurrencyFormat = true;
2139: affix.append(doubled ? "'\u00A4\u00A4"
2140: : "'\u00A4");
2141: continue;
2142: } else if (ch == QUOTE) {
2143: // A quote outside quotes indicates either the opening
2144: // quote or two quotes, which is a quote literal. That is,
2145: // we have the first quote in 'do' or o''clock.
2146: if (ch == QUOTE) {
2147: if ((pos + 1) < pattern.length()
2148: && pattern.charAt(pos + 1) == QUOTE) {
2149: ++pos;
2150: affix.append("''"); // o''clock
2151: } else {
2152: inQuote = true; // 'do'
2153: }
2154: continue;
2155: }
2156: } else if (ch == separator) {
2157: // Don't allow separators before we see digit characters of phase
2158: // 1, and don't allow separators in the second pattern (j == 0).
2159: if (phase == 0 || j == 0)
2160: throw new IllegalArgumentException(
2161: "Unquoted special character '"
2162: + ch
2163: + "' in pattern \""
2164: + pattern + '"');
2165: start = pos + 1;
2166: pos = pattern.length();
2167: continue;
2168: }
2169:
2170: // Next handle characters which are appended directly.
2171: else if (ch == percent) {
2172: if (multiplier != 1)
2173: throw new IllegalArgumentException(
2174: "Too many percent/permille characters in pattern \""
2175: + pattern + '"');
2176: multiplier = 100;
2177: affix.append("'%");
2178: continue;
2179: } else if (ch == perMill) {
2180: if (multiplier != 1)
2181: throw new IllegalArgumentException(
2182: "Too many percent/permille characters in pattern \""
2183: + pattern + '"');
2184: multiplier = 1000;
2185: affix.append("'\u2030");
2186: continue;
2187: } else if (ch == minus) {
2188: affix.append("'-");
2189: continue;
2190: }
2191: }
2192: // Note that if we are within quotes, or if this is an unquoted,
2193: // non-special character, then we usually fall through to here.
2194: affix.append(ch);
2195: break;
2196: case 1:
2197: // Phase one must be identical in the two sub-patterns. We
2198: // enforce this by doing a direct comparison. While
2199: // processing the first sub-pattern, we just record its
2200: // length. While processing the second, we compare
2201: // characters.
2202: if (j == 1)
2203: ++phaseOneLength;
2204: else {
2205: /**
2206: * 1.2 Back-out comment : HShih
2207: * if (ch != pattern.charAt(phaseOneStart++))
2208: * throw new IllegalArgumentException("Subpattern mismatch in \"" +
2209: * pattern + '"');
2210: * phaseTwo = true;
2211: */
2212: if (--phaseOneLength == 0) {
2213: phase = 2;
2214: affix = suffix;
2215: }
2216: continue;
2217: }
2218:
2219: // Process the digits, decimal, and grouping characters. We
2220: // record five pieces of information. We expect the digits
2221: // to occur in the pattern ####0000.####, and we record the
2222: // number of left digits, zero (central) digits, and right
2223: // digits. The position of the last grouping character is
2224: // recorded (should be somewhere within the first two blocks
2225: // of characters), as is the position of the decimal point,
2226: // if any (should be in the zero digits). If there is no
2227: // decimal point, then there should be no right digits.
2228: if (ch == digit) {
2229: if (zeroDigitCount > 0)
2230: ++digitRightCount;
2231: else
2232: ++digitLeftCount;
2233: if (groupingCount >= 0 && decimalPos < 0)
2234: ++groupingCount;
2235: } else if (ch == zeroDigit) {
2236: if (digitRightCount > 0)
2237: throw new IllegalArgumentException(
2238: "Unexpected '0' in pattern \""
2239: + pattern + '"');
2240: ++zeroDigitCount;
2241: if (groupingCount >= 0 && decimalPos < 0)
2242: ++groupingCount;
2243: } else if (ch == groupingSeparator) {
2244: groupingCount = 0;
2245: } else if (ch == decimalSeparator) {
2246: if (decimalPos >= 0)
2247: throw new IllegalArgumentException(
2248: "Multiple decimal separators in pattern \""
2249: + pattern + '"');
2250: decimalPos = digitLeftCount + zeroDigitCount
2251: + digitRightCount;
2252: } else if (ch == exponent) {
2253: if (useExponentialNotation)
2254: throw new IllegalArgumentException(
2255: "Multiple exponential "
2256: + "symbols in pattern \""
2257: + pattern + '"');
2258: useExponentialNotation = true;
2259: minExponentDigits = 0;
2260:
2261: // Use lookahead to parse out the exponential part of the
2262: // pattern, then jump into phase 2.
2263: while (++pos < pattern.length()
2264: && pattern.charAt(pos) == zeroDigit) {
2265: ++minExponentDigits;
2266: ++phaseOneLength;
2267: }
2268:
2269: if ((digitLeftCount + zeroDigitCount) < 1
2270: || minExponentDigits < 1)
2271: throw new IllegalArgumentException(
2272: "Malformed exponential "
2273: + "pattern \"" + pattern
2274: + '"');
2275:
2276: // Transition to phase 2
2277: phase = 2;
2278: affix = suffix;
2279: --pos;
2280: continue;
2281: } else {
2282: phase = 2;
2283: affix = suffix;
2284: --pos;
2285: --phaseOneLength;
2286: continue;
2287: }
2288: break;
2289: }
2290: }
2291: /**
2292: * 1.2 Back-out comment : HShih
2293: * if (phaseTwo && phaseOneLength > 0)
2294: * throw new IllegalArgumentException("Subpattern mismatch in \"" +
2295: * pattern + '"');
2296: */
2297: // Handle patterns with no '0' pattern character. These patterns
2298: // are legal, but must be interpreted. "##.###" -> "#0.###".
2299: // ".###" -> ".0##".
2300: /* We allow patterns of the form "####" to produce a zeroDigitCount of
2301: * zero (got that?); although this seems like it might make it possible
2302: * for format() to produce empty strings, format() checks for this
2303: * condition and outputs a zero digit in this situation. Having a
2304: * zeroDigitCount of zero yields a minimum integer digits of zero, which
2305: * allows proper round-trip patterns. That is, we don't want "#" to
2306: * become "#0" when toPattern() is called (even though that's what it
2307: * really is, semantically). */
2308: if (zeroDigitCount == 0 && digitLeftCount > 0
2309: && decimalPos >= 0) {
2310: // Handle "###.###" and "###." and ".###"
2311: int n = decimalPos;
2312: if (n == 0)
2313: ++n; // Handle ".###"
2314: digitRightCount = digitLeftCount - n;
2315: digitLeftCount = n - 1;
2316: zeroDigitCount = 1;
2317: }
2318:
2319: // Do syntax checking on the digits.
2320: if ((decimalPos < 0 && digitRightCount > 0)
2321: || (decimalPos >= 0 && (decimalPos < digitLeftCount || decimalPos > (digitLeftCount + zeroDigitCount)))
2322: || groupingCount == 0 || inQuote)
2323: throw new IllegalArgumentException(
2324: "Malformed pattern \"" + pattern + '"');
2325:
2326: if (j == 1) {
2327: posPrefixPattern = prefix.toString();
2328: posSuffixPattern = suffix.toString();
2329: negPrefixPattern = posPrefixPattern; // assume these for now
2330: negSuffixPattern = posSuffixPattern;
2331: int digitTotalCount = digitLeftCount + zeroDigitCount
2332: + digitRightCount;
2333: /* The effectiveDecimalPos is the position the decimal is at or
2334: * would be at if there is no decimal. Note that if decimalPos<0,
2335: * then digitTotalCount == digitLeftCount + zeroDigitCount. */
2336: int effectiveDecimalPos = decimalPos >= 0 ? decimalPos
2337: : digitTotalCount;
2338: setMinimumIntegerDigits(effectiveDecimalPos
2339: - digitLeftCount);
2340: setMaximumIntegerDigits(useExponentialNotation ? digitLeftCount
2341: + getMinimumIntegerDigits()
2342: : DOUBLE_INTEGER_DIGITS);
2343: setMaximumFractionDigits(decimalPos >= 0 ? (digitTotalCount - decimalPos)
2344: : 0);
2345: setMinimumFractionDigits(decimalPos >= 0 ? (digitLeftCount
2346: + zeroDigitCount - decimalPos)
2347: : 0);
2348: setGroupingUsed(groupingCount > 0);
2349: this .groupingSize = (groupingCount > 0) ? groupingCount
2350: : 0;
2351: this .multiplier = multiplier;
2352: setDecimalSeparatorAlwaysShown(decimalPos == 0
2353: || decimalPos == digitTotalCount);
2354: } else {
2355: negPrefixPattern = prefix.toString();
2356: negSuffixPattern = suffix.toString();
2357: gotNegative = true;
2358: }
2359: }
2360:
2361: if (pattern.length() == 0) {
2362: posPrefixPattern = posSuffixPattern = "";
2363: setMinimumIntegerDigits(0);
2364: setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
2365: setMinimumFractionDigits(0);
2366: setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
2367: }
2368:
2369: // If there was no negative pattern, or if the negative pattern is identical
2370: // to the positive pattern, then prepend the minus sign to the positive
2371: // pattern to form the negative pattern.
2372: if (!gotNegative
2373: || (negPrefixPattern.equals(posPrefixPattern) && negSuffixPattern
2374: .equals(posSuffixPattern))) {
2375: negSuffixPattern = posSuffixPattern;
2376: negPrefixPattern = "'-" + posPrefixPattern;
2377: }
2378:
2379: expandAffixes();
2380: }
2381:
2382: /**
2383: * Sets the maximum number of digits allowed in the integer portion of a
2384: * number. This override limits the integer digit count to 309.
2385: * @see NumberFormat#setMaximumIntegerDigits
2386: */
2387: public void setMaximumIntegerDigits(int newValue) {
2388: super .setMaximumIntegerDigits(Math.min(newValue,
2389: DOUBLE_INTEGER_DIGITS));
2390: }
2391:
2392: /**
2393: * Sets the minimum number of digits allowed in the integer portion of a
2394: * number. This override limits the integer digit count to 309.
2395: * @see NumberFormat#setMinimumIntegerDigits
2396: */
2397: public void setMinimumIntegerDigits(int newValue) {
2398: super .setMinimumIntegerDigits(Math.min(newValue,
2399: DOUBLE_INTEGER_DIGITS));
2400: }
2401:
2402: /**
2403: * Sets the maximum number of digits allowed in the fraction portion of a
2404: * number. This override limits the fraction digit count to 340.
2405: * @see NumberFormat#setMaximumFractionDigits
2406: */
2407: public void setMaximumFractionDigits(int newValue) {
2408: super .setMaximumFractionDigits(Math.min(newValue,
2409: DOUBLE_FRACTION_DIGITS));
2410: }
2411:
2412: /**
2413: * Sets the minimum number of digits allowed in the fraction portion of a
2414: * number. This override limits the fraction digit count to 340.
2415: * @see NumberFormat#setMinimumFractionDigits
2416: */
2417: public void setMinimumFractionDigits(int newValue) {
2418: super .setMinimumFractionDigits(Math.min(newValue,
2419: DOUBLE_FRACTION_DIGITS));
2420: }
2421:
2422: /**
2423: * Gets the currency used by this decimal format when formatting
2424: * currency values.
2425: * The currency is obtained by calling
2426: * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
2427: * on this number format's symbols.
2428: *
2429: * @return the currency used by this decimal format, or <code>null</code>
2430: * @since 1.4
2431: */
2432: public Currency getCurrency() {
2433: return symbols.getCurrency();
2434: }
2435:
2436: /**
2437: * Sets the currency used by this number format when formatting
2438: * currency values. This does not update the minimum or maximum
2439: * number of fraction digits used by the number format.
2440: * The currency is set by calling
2441: * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
2442: * on this number format's symbols.
2443: *
2444: * @param currency the new currency to be used by this decimal format
2445: * @exception NullPointerException if <code>currency</code> is null
2446: * @since 1.4
2447: */
2448: public void setCurrency(Currency currency) {
2449: if (currency != symbols.getCurrency()) {
2450: symbols.setCurrency(currency);
2451: if (isCurrencyFormat) {
2452: expandAffixes();
2453: }
2454: }
2455: }
2456:
2457: /**
2458: * Adjusts the minimum and maximum fraction digits to values that
2459: * are reasonable for the currency's default fraction digits.
2460: */
2461: void adjustForCurrencyDefaultFractionDigits() {
2462: Currency currency = symbols.getCurrency();
2463: if (currency == null) {
2464: try {
2465: currency = Currency.getInstance(symbols
2466: .getInternationalCurrencySymbol());
2467: } catch (IllegalArgumentException e) {
2468: }
2469: }
2470: if (currency != null) {
2471: int digits = currency.getDefaultFractionDigits();
2472: if (digits != -1) {
2473: int oldMinDigits = getMinimumFractionDigits();
2474: // Common patterns are "#.##", "#.00", "#".
2475: // Try to adjust all of them in a reasonable way.
2476: if (oldMinDigits == getMaximumFractionDigits()) {
2477: setMinimumFractionDigits(digits);
2478: setMaximumFractionDigits(digits);
2479: } else {
2480: setMinimumFractionDigits(Math.min(digits,
2481: oldMinDigits));
2482: setMaximumFractionDigits(digits);
2483: }
2484: }
2485: }
2486: }
2487:
2488: /**
2489: * First, read the default serializable fields from the stream. Then
2490: * if <code>serialVersionOnStream</code> is less than 1, indicating that
2491: * the stream was written by JDK 1.1, initialize <code>useExponentialNotation</code>
2492: * to false, since it was not present in JDK 1.1.
2493: * Finally, set serialVersionOnStream back to the maximum allowed value so that
2494: * default serialization will work properly if this object is streamed out again.
2495: *
2496: * <p>If the minimum or maximum integer digit count is larger than
2497: * <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or maximum fraction
2498: * digit count is larger than <code>DOUBLE_FRACTION_DIGITS</code>, then the
2499: * stream data is invalid and this method throws an
2500: * <code>InvalidObjectException</code>.
2501: *
2502: * <p>Stream versions older than 2 will not have the affix pattern variables
2503: * <code>posPrefixPattern</code> etc. As a result, they will be initialized
2504: * to <code>null</code>, which means the affix strings will be taken as
2505: * literal values. This is exactly what we want, since that corresponds to
2506: * the pre-version-2 behavior.
2507: */
2508: private void readObject(ObjectInputStream stream)
2509: throws IOException, ClassNotFoundException {
2510: stream.defaultReadObject();
2511: // We only need to check the maximum counts because NumberFormat
2512: // .readObject has already ensured that the maximum is greater than the
2513: // minimum count.
2514: if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS
2515: || getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
2516: throw new InvalidObjectException("Digit count out of range");
2517: }
2518: if (serialVersionOnStream < 1) {
2519: // Didn't have exponential fields
2520: useExponentialNotation = false;
2521: }
2522: serialVersionOnStream = currentSerialVersion;
2523: digitList = new DigitList();
2524: }
2525:
2526: //----------------------------------------------------------------------
2527: // INSTANCE VARIABLES
2528: //----------------------------------------------------------------------
2529:
2530: private transient DigitList digitList = new DigitList();
2531:
2532: /**
2533: * The symbol used as a prefix when formatting positive numbers, e.g. "+".
2534: *
2535: * @serial
2536: * @see #getPositivePrefix
2537: */
2538: private String positivePrefix = "";
2539:
2540: /**
2541: * The symbol used as a suffix when formatting positive numbers.
2542: * This is often an empty string.
2543: *
2544: * @serial
2545: * @see #getPositiveSuffix
2546: */
2547: private String positiveSuffix = "";
2548:
2549: /**
2550: * The symbol used as a prefix when formatting negative numbers, e.g. "-".
2551: *
2552: * @serial
2553: * @see #getNegativePrefix
2554: */
2555: private String negativePrefix = "-";
2556:
2557: /**
2558: * The symbol used as a suffix when formatting negative numbers.
2559: * This is often an empty string.
2560: *
2561: * @serial
2562: * @see #getNegativeSuffix
2563: */
2564: private String negativeSuffix = "";
2565:
2566: /**
2567: * The prefix pattern for non-negative numbers. This variable corresponds
2568: * to <code>positivePrefix</code>.
2569: *
2570: * <p>This pattern is expanded by the method <code>expandAffix()</code> to
2571: * <code>positivePrefix</code> to update the latter to reflect changes in
2572: * <code>symbols</code>. If this variable is <code>null</code> then
2573: * <code>positivePrefix</code> is taken as a literal value that does not
2574: * change when <code>symbols</code> changes. This variable is always
2575: * <code>null</code> for <code>DecimalFormat</code> objects older than
2576: * stream version 2 restored from stream.
2577: *
2578: * @serial
2579: * @since 1.3
2580: */
2581: private String posPrefixPattern;
2582:
2583: /**
2584: * The suffix pattern for non-negative numbers. This variable corresponds
2585: * to <code>positiveSuffix</code>. This variable is analogous to
2586: * <code>posPrefixPattern</code>; see that variable for further
2587: * documentation.
2588: *
2589: * @serial
2590: * @since 1.3
2591: */
2592: private String posSuffixPattern;
2593:
2594: /**
2595: * The prefix pattern for negative numbers. This variable corresponds
2596: * to <code>negativePrefix</code>. This variable is analogous to
2597: * <code>posPrefixPattern</code>; see that variable for further
2598: * documentation.
2599: *
2600: * @serial
2601: * @since 1.3
2602: */
2603: private String negPrefixPattern;
2604:
2605: /**
2606: * The suffix pattern for negative numbers. This variable corresponds
2607: * to <code>negativeSuffix</code>. This variable is analogous to
2608: * <code>posPrefixPattern</code>; see that variable for further
2609: * documentation.
2610: *
2611: * @serial
2612: * @since 1.3
2613: */
2614: private String negSuffixPattern;
2615:
2616: /**
2617: * The multiplier for use in percent, permill, etc.
2618: *
2619: * @serial
2620: * @see #getMultiplier
2621: */
2622: private int multiplier = 1;
2623:
2624: /**
2625: * The number of digits between grouping separators in the integer
2626: * portion of a number. Must be greater than 0 if
2627: * <code>NumberFormat.groupingUsed</code> is true.
2628: *
2629: * @serial
2630: * @see #getGroupingSize
2631: * @see java.text.NumberFormat#isGroupingUsed
2632: */
2633: private byte groupingSize = 3; // invariant, > 0 if useThousands
2634:
2635: /**
2636: * If true, forces the decimal separator to always appear in a formatted
2637: * number, even if the fractional part of the number is zero.
2638: *
2639: * @serial
2640: * @see #isDecimalSeparatorAlwaysShown
2641: */
2642: private boolean decimalSeparatorAlwaysShown = false;
2643:
2644: /**
2645: * True if this object represents a currency format. This determines
2646: * whether the monetary decimal separator is used instead of the normal one.
2647: */
2648: private transient boolean isCurrencyFormat = false;
2649:
2650: /**
2651: * The <code>DecimalFormatSymbols</code> object used by this format.
2652: * It contains the symbols used to format numbers, e.g. the grouping separator,
2653: * decimal separator, and so on.
2654: *
2655: * @serial
2656: * @see #setDecimalFormatSymbols
2657: * @see java.text.DecimalFormatSymbols
2658: */
2659: private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
2660:
2661: /**
2662: * True to force the use of exponential (i.e. scientific) notation when formatting
2663: * numbers.
2664: *
2665: * @serial
2666: * @since 1.2
2667: */
2668: private boolean useExponentialNotation; // Newly persistent in the Java 2 platform
2669:
2670: /**
2671: * FieldPositions describing the positive prefix String. This is
2672: * lazily created. Use <code>getPositivePrefixFieldPositions</code>
2673: * when needed.
2674: */
2675: private transient FieldPosition[] positivePrefixFieldPositions;
2676:
2677: /**
2678: * FieldPositions describing the positive suffix String. This is
2679: * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
2680: * when needed.
2681: */
2682: private transient FieldPosition[] positiveSuffixFieldPositions;
2683:
2684: /**
2685: * FieldPositions describing the negative prefix String. This is
2686: * lazily created. Use <code>getNegativePrefixFieldPositions</code>
2687: * when needed.
2688: */
2689: private transient FieldPosition[] negativePrefixFieldPositions;
2690:
2691: /**
2692: * FieldPositions describing the negative suffix String. This is
2693: * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
2694: * when needed.
2695: */
2696: private transient FieldPosition[] negativeSuffixFieldPositions;
2697:
2698: /**
2699: * The minimum number of digits used to display the exponent when a number is
2700: * formatted in exponential notation. This field is ignored if
2701: * <code>useExponentialNotation</code> is not true.
2702: *
2703: * @serial
2704: * @since 1.2
2705: */
2706: private byte minExponentDigits; // Newly persistent in the Java 2 platform
2707:
2708: //----------------------------------------------------------------------
2709:
2710: static final int currentSerialVersion = 2;
2711:
2712: /**
2713: * The internal serial version which says which version was written.
2714: * Possible values are:
2715: * <ul>
2716: * <li><b>0</b> (default): versions before the Java 2 platform v1.2
2717: * <li><b>1</b>: version for 1.2, which includes the two new fields
2718: * <code>useExponentialNotation</code> and <code>minExponentDigits</code>.
2719: * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
2720: * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
2721: * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
2722: * </ul>
2723: * @since 1.2
2724: * @serial
2725: */
2726: private int serialVersionOnStream = currentSerialVersion;
2727:
2728: //----------------------------------------------------------------------
2729: // CONSTANTS
2730: //----------------------------------------------------------------------
2731:
2732: // Constants for characters used in programmatic (unlocalized) patterns.
2733: private static final char PATTERN_ZERO_DIGIT = '0';
2734: private static final char PATTERN_GROUPING_SEPARATOR = ',';
2735: private static final char PATTERN_DECIMAL_SEPARATOR = '.';
2736: private static final char PATTERN_PER_MILLE = '\u2030';
2737: private static final char PATTERN_PERCENT = '%';
2738: private static final char PATTERN_DIGIT = '#';
2739: private static final char PATTERN_SEPARATOR = ';';
2740: private static final char PATTERN_EXPONENT = 'E';
2741: private static final char PATTERN_MINUS = '-';
2742:
2743: /**
2744: * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
2745: * is used in patterns and substitued with either the currency symbol,
2746: * or if it is doubled, with the international currency symbol. If the
2747: * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
2748: * replaced with the monetary decimal separator.
2749: *
2750: * The CURRENCY_SIGN is not localized.
2751: */
2752: private static final char CURRENCY_SIGN = '\u00A4';
2753:
2754: private static final char QUOTE = '\'';
2755:
2756: private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
2757:
2758: // Upper limit on integer and fraction digits for a Java double
2759: static final int DOUBLE_INTEGER_DIGITS = 309;
2760: static final int DOUBLE_FRACTION_DIGITS = 340;
2761:
2762: // Proclaim JDK 1.1 serial compatibility.
2763: static final long serialVersionUID = 864413376551465018L;
2764:
2765: /**
2766: * Cache to hold the NumberPattern of a Locale.
2767: */
2768: private static Hashtable cachedLocaleData = new Hashtable(3);
2769: }
|