0001: //##header
0002: /*
0003: *******************************************************************************
0004: * Copyright (C) 1996-2006, International Business Machines Corporation and *
0005: * others. All Rights Reserved. *
0006: *******************************************************************************
0007: */
0008: package com.ibm.icu.text;
0009:
0010: import java.io.IOException;
0011: import java.io.ObjectInputStream;
0012: import java.io.ObjectOutputStream;
0013: import java.math.BigInteger;
0014: import java.text.AttributedCharacterIterator;
0015: import java.text.AttributedString;
0016: import java.text.ChoiceFormat;
0017: import java.text.FieldPosition;
0018: import java.text.Format;
0019: import java.text.ParsePosition;
0020: import java.util.ArrayList;
0021:
0022: import com.ibm.icu.impl.UCharacterProperty;
0023: import com.ibm.icu.lang.UCharacter;
0024: import com.ibm.icu.math.BigDecimal;
0025: import com.ibm.icu.util.Currency;
0026: import com.ibm.icu.util.CurrencyAmount;
0027: import com.ibm.icu.util.ULocale;
0028:
0029: /**
0030: * <code>DecimalFormat</code> is a concrete subclass of
0031: * {@link NumberFormat} that formats decimal numbers. It has a variety of
0032: * features designed to make it possible to parse and format numbers in any
0033: * locale, including support for Western, Arabic, or Indic digits. It also
0034: * supports different flavors of numbers, including integers ("123"),
0035: * fixed-point numbers ("123.4"), scientific notation ("1.23E4"), percentages
0036: * ("12%"), and currency amounts ("$123"). All of these flavors can be easily
0037: * localized.
0038: *
0039: * <p><strong>This is an enhanced version of <code>DecimalFormat</code> that
0040: * is based on the standard version in the JDK. New or changed functionality
0041: * is labeled
0042: * <strong><font face=helvetica color=red>NEW</font></strong> or
0043: * <strong><font face=helvetica color=red>CHANGED</font></strong>.</strong>
0044: *
0045: * <p>To obtain a {@link NumberFormat} for a specific locale (including the
0046: * default locale) call one of <code>NumberFormat</code>'s factory methods such
0047: * as {@link NumberFormat#getInstance}. Do not call the <code>DecimalFormat</code>
0048: * constructors directly, unless you know what you are doing, since the
0049: * {@link NumberFormat} factory methods may return subclasses other than
0050: * <code>DecimalFormat</code>. If you need to customize the format object, do
0051: * something like this:
0052: *
0053: * <blockquote><pre>
0054: * NumberFormat f = NumberFormat.getInstance(loc);
0055: * if (f instanceof DecimalFormat) {
0056: * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
0057: * }</pre></blockquote>
0058: *
0059: * <p><strong>Example Usage</strong>
0060: *
0061: * <blockquote><pre>
0062: * <strong>// Print out a number using the localized number, currency,
0063: * // and percent format for each locale</strong>
0064: * Locale[] locales = NumberFormat.getAvailableLocales();
0065: * double myNumber = -1234.56;
0066: * NumberFormat format;
0067: * for (int j=0; j<3; ++j) {
0068: * System.out.println("FORMAT");
0069: * for (int i = 0; i < locales.length; ++i) {
0070: * if (locales[i].getCountry().length() == 0) {
0071: * // Skip language-only locales
0072: * continue;
0073: * }
0074: * System.out.print(locales[i].getDisplayName());
0075: * switch (j) {
0076: * case 0:
0077: * format = NumberFormat.getInstance(locales[i]); break;
0078: * case 1:
0079: * format = NumberFormat.getCurrencyInstance(locales[i]); break;
0080: * default:
0081: * format = NumberFormat.getPercentInstance(locales[i]); break;
0082: * }
0083: * try {
0084: * // Assume format is a DecimalFormat
0085: * System.out.print(": " + ((DecimalFormat) format).toPattern()
0086: * + " -> " + form.format(myNumber));
0087: * } catch (Exception e) {}
0088: * try {
0089: * System.out.println(" -> " + format.parse(form.format(myNumber)));
0090: * } catch (ParseException e) {}
0091: * }
0092: * }</pre></blockquote>
0093: *
0094: * <h4>Patterns</h4>
0095: *
0096: * <p>A <code>DecimalFormat</code> consists of a <em>pattern</em> and a set of
0097: * <em>symbols</em>. The pattern may be set directly using
0098: * {@link #applyPattern}, or indirectly using other API methods which
0099: * manipulate aspects of the pattern, such as the minimum number of integer
0100: * digits. The symbols are stored in a {@link DecimalFormatSymbols}
0101: * object. When using the {@link NumberFormat} factory methods, the
0102: * pattern and symbols are read from ICU's locale data.
0103: *
0104: * <h4>Special Pattern Characters</h4>
0105: *
0106: * <p>Many characters in a pattern are taken literally; they are matched during
0107: * parsing and output unchanged during formatting. Special characters, on the
0108: * other hand, stand for other characters, strings, or classes of characters.
0109: * For example, the '#' character is replaced by a localized digit. Often the
0110: * replacement character is the same as the pattern character; in the U.S. locale,
0111: * the ',' grouping character is replaced by ','. However, the replacement is
0112: * still happening, and if the symbols are modified, the grouping character
0113: * changes. Some special characters affect the behavior of the formatter by
0114: * their presence; for example, if the percent character is seen, then the
0115: * value is multiplied by 100 before being displayed.
0116: *
0117: * <p>To insert a special character in a pattern as a literal, that is, without
0118: * any special meaning, the character must be quoted. There are some exceptions to
0119: * this which are noted below.
0120: *
0121: * <p>The characters listed here are used in non-localized patterns. Localized
0122: * patterns use the corresponding characters taken from this formatter's
0123: * {@link DecimalFormatSymbols} object instead, and these characters lose
0124: * their special status. Two exceptions are the currency sign and quote, which
0125: * are not localized.
0126: *
0127: * <blockquote>
0128: * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
0129: * location, localized, and meaning.">
0130: * <tr bgcolor="#ccccff">
0131: * <th align=left>Symbol
0132: * <th align=left>Location
0133: * <th align=left>Localized?
0134: * <th align=left>Meaning
0135: * <tr valign=top>
0136: * <td><code>0</code>
0137: * <td>Number
0138: * <td>Yes
0139: * <td>Digit
0140: * <tr valign=top bgcolor="#eeeeff">
0141: * <td><code>1-9</code>
0142: * <td>Number
0143: * <td>Yes
0144: * <td><strong><font face=helvetica color=red>NEW</font></strong>
0145: * '1' through '9' indicate rounding.
0146: * <tr valign=top>
0147: * <td><code>@</code>
0148: * <td>Number
0149: * <td>No
0150: * <td><strong><font face=helvetica color=red>NEW</font></strong>
0151: * Significant digit
0152: * <tr valign=top bgcolor="#eeeeff">
0153: * <td><code>#</code>
0154: * <td>Number
0155: * <td>Yes
0156: * <td>Digit, zero shows as absent
0157: * <tr valign=top>
0158: * <td><code>.</code>
0159: * <td>Number
0160: * <td>Yes
0161: * <td>Decimal separator or monetary decimal separator
0162: * <tr valign=top bgcolor="#eeeeff">
0163: * <td><code>-</code>
0164: * <td>Number
0165: * <td>Yes
0166: * <td>Minus sign
0167: * <tr valign=top>
0168: * <td><code>,</code>
0169: * <td>Number
0170: * <td>Yes
0171: * <td>Grouping separator
0172: * <tr valign=top bgcolor="#eeeeff">
0173: * <td><code>E</code>
0174: * <td>Number
0175: * <td>Yes
0176: * <td>Separates mantissa and exponent in scientific notation.
0177: * <em>Need not be quoted in prefix or suffix.</em>
0178: * <tr valign=top>
0179: * <td><code>+</code>
0180: * <td>Exponent
0181: * <td>Yes
0182: * <td><strong><font face=helvetica color=red>NEW</font></strong>
0183: * Prefix positive exponents with localized plus sign.
0184: * <em>Need not be quoted in prefix or suffix.</em>
0185: * <tr valign=top bgcolor="#eeeeff">
0186: * <td><code>;</code>
0187: * <td>Subpattern boundary
0188: * <td>Yes
0189: * <td>Separates positive and negative subpatterns
0190: * <tr valign=top>
0191: * <td><code>%</code>
0192: * <td>Prefix or suffix
0193: * <td>Yes
0194: * <td>Multiply by 100 and show as percentage
0195: * <tr valign=top bgcolor="#eeeeff">
0196: * <td><code>\u2030</code>
0197: * <td>Prefix or suffix
0198: * <td>Yes
0199: * <td>Multiply by 1000 and show as per mille
0200: * <tr valign=top>
0201: * <td><code>¤</code> (<code>\u00A4</code>)
0202: * <td>Prefix or suffix
0203: * <td>No
0204: * <td>Currency sign, replaced by currency symbol. If
0205: * doubled, replaced by international currency symbol.
0206: * If present in a pattern, the monetary decimal separator
0207: * is used instead of the decimal separator.
0208: * <tr valign=top bgcolor="#eeeeff">
0209: * <td><code>'</code>
0210: * <td>Prefix or suffix
0211: * <td>No
0212: * <td>Used to quote special characters in a prefix or suffix,
0213: * for example, <code>"'#'#"</code> formats 123 to
0214: * <code>"#123"</code>. To create a single quote
0215: * itself, use two in a row: <code>"# o''clock"</code>.
0216: * <tr valign=top>
0217: * <td><code>*</code>
0218: * <td>Prefix or suffix boundary
0219: * <td>Yes
0220: * <td><strong><font face=helvetica color=red>NEW</font></strong>
0221: * Pad escape, precedes pad character
0222: * </table>
0223: * </blockquote>
0224: *
0225: * <p>A <code>DecimalFormat</code> pattern contains a postive and negative
0226: * subpattern, for example, "#,##0.00;(#,##0.00)". Each subpattern has a
0227: * prefix, a numeric part, and a suffix. If there is no explicit negative
0228: * subpattern, the negative subpattern is the localized minus sign prefixed to the
0229: * positive subpattern. That is, "0.00" alone is equivalent to "0.00;-0.00". If there
0230: * is an explicit negative subpattern, it serves only to specify the negative
0231: * prefix and suffix; the number of digits, minimal digits, and other
0232: * characteristics are ignored in the negative subpattern. That means that
0233: * "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)".
0234: *
0235: * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
0236: * thousands separators, decimal separators, etc. may be set to arbitrary
0237: * values, and they will appear properly during formatting. However, care must
0238: * be taken that the symbols and strings do not conflict, or parsing will be
0239: * unreliable. For example, either the positive and negative prefixes or the
0240: * suffixes must be distinct for {@link #parse} to be able
0241: * to distinguish positive from negative values. Another example is that the
0242: * decimal separator and thousands separator should be distinct characters, or
0243: * parsing will be impossible.
0244: *
0245: * <p>The <em>grouping separator</em> is a character that separates clusters of
0246: * integer digits to make large numbers more legible. It commonly used for
0247: * thousands, but in some locales it separates ten-thousands. The <em>grouping
0248: * size</em> is the number of digits between the grouping separators, such as 3
0249: * for "100,000,000" or 4 for "1 0000 0000". There are actually two different
0250: * grouping sizes: One used for the least significant integer digits, the
0251: * <em>primary grouping size</em>, and one used for all others, the
0252: * <em>secondary grouping size</em>. In most locales these are the same, but
0253: * sometimes they are different. For example, if the primary grouping interval
0254: * is 3, and the secondary is 2, then this corresponds to the pattern
0255: * "#,##,##0", and the number 123456789 is formatted as "12,34,56,789". If a
0256: * pattern contains multiple grouping separators, the interval between the last
0257: * one and the end of the integer defines the primary grouping size, and the
0258: * interval between the last two defines the secondary grouping size. All others
0259: * are ignored, so "#,##,###,####" == "###,###,####" == "##,#,###,####".
0260: *
0261: * <p>Illegal patterns, such as "#.#.#" or "#.###,###", will cause
0262: * <code>DecimalFormat</code> to throw an {@link IllegalArgumentException}
0263: * with a message that describes the problem.
0264: *
0265: * <h4>Pattern BNF</h4>
0266: *
0267: * <pre>
0268: * pattern := subpattern (';' subpattern)?
0269: * subpattern := prefix? number exponent? suffix?
0270: * number := (integer ('.' fraction)?) | sigDigits
0271: * prefix := '\u0000'..'\uFFFD' - specialCharacters
0272: * suffix := '\u0000'..'\uFFFD' - specialCharacters
0273: * integer := '#'* '0'* '0'
0274: * fraction := '0'* '#'*
0275: * sigDigits := '#'* '@' '@'* '#'*
0276: * exponent := 'E' '+'? '0'* '0'
0277: * padSpec := '*' padChar
0278: * padChar := '\u0000'..'\uFFFD' - quote
0279: *  
0280: * Notation:
0281: * X* 0 or more instances of X
0282: * X? 0 or 1 instances of X
0283: * X|Y either X or Y
0284: * C..D any character from C up to D, inclusive
0285: * S-T characters in S, except those in T
0286: * </pre>
0287: * The first subpattern is for positive numbers. The second (optional)
0288: * subpattern is for negative numbers.
0289: *
0290: * <p>Not indicated in the BNF syntax above:
0291: *
0292: * <ul><li>The grouping separator ',' can occur inside the integer and
0293: * sigDigits elements, between any two pattern characters of that
0294: * element, as long as the integer or sigDigits element is not
0295: * followed by the exponent element.
0296: *
0297: * <li><font color=red face=helvetica><strong>NEW</strong></font>
0298: * Two grouping intervals are recognized: That between the
0299: * decimal point and the first grouping symbol, and that
0300: * between the first and second grouping symbols. These
0301: * intervals are identical in most locales, but in some
0302: * locales they differ. For example, the pattern
0303: * "#,##,###" formats the number 123456789 as
0304: * "12,34,56,789".</li>
0305: *
0306: * <li>
0307: * <strong><font face=helvetica color=red>NEW</font></strong>
0308: * The pad specifier <code>padSpec</code> may appear before the prefix,
0309: * after the prefix, before the suffix, after the suffix, or not at all.
0310: *
0311: * <li>
0312: * <strong><font face=helvetica color=red>NEW</font></strong>
0313: * In place of '0', the digits '1' through '9' may be used to
0314: * indicate a rounding increment.
0315: * </ul>
0316: *
0317: * <h4>Parsing</h4>
0318: *
0319: * <p><code>DecimalFormat</code> parses all Unicode characters that represent
0320: * decimal digits, as defined by {@link UCharacter#digit}. In addition,
0321: * <code>DecimalFormat</code> also recognizes as digits the ten consecutive
0322: * characters starting with the localized zero digit defined in the
0323: * {@link DecimalFormatSymbols} object. During formatting, the
0324: * {@link DecimalFormatSymbols}-based digits are output.
0325: *
0326: * <p>During parsing, grouping separators are ignored.
0327: *
0328: * <p>If {@link #parse(String, ParsePosition)} fails to parse
0329: * a string, it returns <code>null</code> and leaves the parse position
0330: * unchanged. The convenience method {@link #parse(String)}
0331: * indicates parse failure by throwing a {@link java.text.ParseException}.
0332: *
0333: * <h4>Formatting</h4>
0334: *
0335: * <p>Formatting is guided by several parameters, all of which can be
0336: * specified either using a pattern or using the API. The following
0337: * description applies to formats that do not use <a href="#sci">scientific
0338: * notation</a> or <a href="#sigdig">significant digits</a>.
0339: *
0340: * <ul><li>If the number of actual integer digits exceeds the
0341: * <em>maximum integer digits</em>, then only the least significant
0342: * digits are shown. For example, 1997 is formatted as "97" if the
0343: * maximum integer digits is set to 2.
0344: *
0345: * <li>If the number of actual integer digits is less than the
0346: * <em>minimum integer digits</em>, then leading zeros are added. For
0347: * example, 1997 is formatted as "01997" if the minimum integer digits
0348: * is set to 5.
0349: *
0350: * <li>If the number of actual fraction digits exceeds the <em>maximum
0351: * fraction digits</em>, then half-even rounding it performed to the
0352: * maximum fraction digits. For example, 0.125 is formatted as "0.12"
0353: * if the maximum fraction digits is 2. This behavior can be changed
0354: * by specifying a rounding increment and a rounding mode.
0355: *
0356: * <li>If the number of actual fraction digits is less than the
0357: * <em>minimum fraction digits</em>, then trailing zeros are added.
0358: * For example, 0.125 is formatted as "0.1250" if the mimimum fraction
0359: * digits is set to 4.
0360: *
0361: * <li>Trailing fractional zeros are not displayed if they occur
0362: * <em>j</em> positions after the decimal, where <em>j</em> is less
0363: * than the maximum fraction digits. For example, 0.10004 is
0364: * formatted as "0.1" if the maximum fraction digits is four or less.
0365: * </ul>
0366: *
0367: * <p><strong>Special Values</strong>
0368: *
0369: * <p><code>NaN</code> is represented as a single character, typically
0370: * <code>\uFFFD</code>. This character is determined by the
0371: * {@link DecimalFormatSymbols} object. This is the only value for which
0372: * the prefixes and suffixes are not used.
0373: *
0374: * <p>Infinity is represented as a single character, typically
0375: * <code>\u221E</code>, with the positive or negative prefixes and suffixes
0376: * applied. The infinity character is determined by the
0377: * {@link DecimalFormatSymbols} object.
0378: *
0379: * <a name="sci"><h4>Scientific Notation</h4></a>
0380: *
0381: * <p>Numbers in scientific notation are expressed as the product of a mantissa
0382: * and a power of ten, for example, 1234 can be expressed as 1.234 x 10<sup>3</sup>. The
0383: * mantissa is typically in the half-open interval [1.0, 10.0) or sometimes [0.0, 1.0),
0384: * but it need not be. <code>DecimalFormat</code> supports arbitrary mantissas.
0385: * <code>DecimalFormat</code> can be instructed to use scientific
0386: * notation through the API or through the pattern. In a pattern, the exponent
0387: * character immediately followed by one or more digit characters indicates
0388: * scientific notation. Example: "0.###E0" formats the number 1234 as
0389: * "1.234E3".
0390: *
0391: * <ul>
0392: * <li>The number of digit characters after the exponent character gives the
0393: * minimum exponent digit count. There is no maximum. Negative exponents are
0394: * formatted using the localized minus sign, <em>not</em> the prefix and suffix
0395: * from the pattern. This allows patterns such as "0.###E0 m/s". To prefix
0396: * positive exponents with a localized plus sign, specify '+' between the
0397: * exponent and the digits: "0.###E+0" will produce formats "1E+1", "1E+0",
0398: * "1E-1", etc. (In localized patterns, use the localized plus sign rather than
0399: * '+'.)
0400: *
0401: * <li>The minimum number of integer digits is achieved by adjusting the
0402: * exponent. Example: 0.00123 formatted with "00.###E0" yields "12.3E-4". This
0403: * only happens if there is no maximum number of integer digits. If there is a
0404: * maximum, then the minimum number of integer digits is fixed at one.
0405: *
0406: * <li>The maximum number of integer digits, if present, specifies the exponent
0407: * grouping. The most common use of this is to generate <em>engineering
0408: * notation</em>, in which the exponent is a multiple of three, e.g.,
0409: * "##0.###E0". The number 12345 is formatted using "##0.####E0" as "12.345E3".
0410: *
0411: * <li>When using scientific notation, the formatter controls the
0412: * digit counts using significant digits logic. The maximum number of
0413: * significant digits limits the total number of integer and fraction
0414: * digits that will be shown in the mantissa; it does not affect
0415: * parsing. For example, 12345 formatted with "##0.##E0" is "12.3E3".
0416: * See the section on significant digits for more details.
0417: *
0418: * <li>The number of significant digits shown is determined as
0419: * follows: If areSignificantDigitsUsed() returns false, then the
0420: * minimum number of significant digits shown is one, and the maximum
0421: * number of significant digits shown is the sum of the <em>minimum
0422: * integer</em> and <em>maximum fraction</em> digits, and is
0423: * unaffected by the maximum integer digits. If this sum is zero,
0424: * then all significant digits are shown. If
0425: * areSignificantDigitsUsed() returns true, then the significant digit
0426: * counts are specified by getMinimumSignificantDigits() and
0427: * getMaximumSignificantDigits(). In this case, the number of
0428: * integer digits is fixed at one, and there is no exponent grouping.
0429: *
0430: * <li>Exponential patterns may not contain grouping separators.
0431: * </ul>
0432: *
0433: * <a name="sigdig"><h4>
0434: * <strong><font face=helvetica color=red>NEW</font></strong>
0435: * Significant Digits</h4></a>
0436: *
0437: * <code>DecimalFormat</code> has two ways of controlling how many
0438: * digits are shows: (a) significant digits counts, or (b) integer and
0439: * fraction digit counts. Integer and fraction digit counts are
0440: * described above. When a formatter is using significant digits
0441: * counts, the number of integer and fraction digits is not specified
0442: * directly, and the formatter settings for these counts are ignored.
0443: * Instead, the formatter uses however many integer and fraction
0444: * digits are required to display the specified number of significant
0445: * digits. Examples:
0446: *
0447: * <blockquote>
0448: * <table border=0 cellspacing=3 cellpadding=0>
0449: * <tr bgcolor="#ccccff">
0450: * <th align=left>Pattern
0451: * <th align=left>Minimum significant digits
0452: * <th align=left>Maximum significant digits
0453: * <th align=left>Number
0454: * <th align=left>Output of format()
0455: * <tr valign=top>
0456: * <td><code>@@@</code>
0457: * <td>3
0458: * <td>3
0459: * <td>12345
0460: * <td><code>12300</code>
0461: * <tr valign=top bgcolor="#eeeeff">
0462: * <td><code>@@@</code>
0463: * <td>3
0464: * <td>3
0465: * <td>0.12345
0466: * <td><code>0.123</code>
0467: * <tr valign=top>
0468: * <td><code>@@##</code>
0469: * <td>2
0470: * <td>4
0471: * <td>3.14159
0472: * <td><code>3.142</code>
0473: * <tr valign=top bgcolor="#eeeeff">
0474: * <td><code>@@##</code>
0475: * <td>2
0476: * <td>4
0477: * <td>1.23004
0478: * <td><code>1.23</code>
0479: * </table>
0480: * </blockquote>
0481: *
0482: * <ul>
0483: * <li>Significant digit counts may be expressed using patterns that
0484: * specify a minimum and maximum number of significant digits. These
0485: * are indicated by the <code>'@'</code> and <code>'#'</code>
0486: * characters. The minimum number of significant digits is the number
0487: * of <code>'@'</code> characters. The maximum number of significant
0488: * digits is the number of <code>'@'</code> characters plus the number
0489: * of <code>'#'</code> characters following on the right. For
0490: * example, the pattern <code>"@@@"</code> indicates exactly 3
0491: * significant digits. The pattern <code>"@##"</code> indicates from
0492: * 1 to 3 significant digits. Trailing zero digits to the right of
0493: * the decimal separator are suppressed after the minimum number of
0494: * significant digits have been shown. For example, the pattern
0495: * <code>"@##"</code> formats the number 0.1203 as
0496: * <code>"0.12"</code>.
0497: *
0498: * <li>If a pattern uses significant digits, it may not contain a
0499: * decimal separator, nor the <code>'0'</code> pattern character.
0500: * Patterns such as <code>"@00"</code> or <code>"@.###"</code> are
0501: * disallowed.
0502: *
0503: * <li>Any number of <code>'#'</code> characters may be prepended to
0504: * the left of the leftmost <code>'@'</code> character. These have no
0505: * effect on the minimum and maximum significant digits counts, but
0506: * may be used to position grouping separators. For example,
0507: * <code>"#,#@#"</code> indicates a minimum of one significant digits,
0508: * a maximum of two significant digits, and a grouping size of three.
0509: *
0510: * <li>In order to enable significant digits formatting, use a pattern
0511: * containing the <code>'@'</code> pattern character. Alternatively,
0512: * call {@link #setSignificantDigitsUsed setSignificantDigitsUsed(true)}.
0513: *
0514: * <li>In order to disable significant digits formatting, use a
0515: * pattern that does not contain the <code>'@'</code> pattern
0516: * character. Alternatively, call {@link #setSignificantDigitsUsed
0517: * setSignificantDigitsUsed(false)}.
0518: *
0519: * <li>The number of significant digits has no effect on parsing.
0520: *
0521: * <li>Significant digits may be used together with exponential notation. Such
0522: * patterns are equivalent to a normal exponential pattern with a minimum and
0523: * maximum integer digit count of one, a minimum fraction digit count of
0524: * <code>getMinimumSignificantDigits() - 1</code>, and a maximum fraction digit
0525: * count of <code>getMaximumSignificantDigits() - 1</code>. For example, the
0526: * pattern <code>"@@###E0"</code> is equivalent to <code>"0.0###E0"</code>.
0527: *
0528: * <li>If signficant digits are in use, then the integer and fraction
0529: * digit counts, as set via the API, are ignored. If significant
0530: * digits are not in use, then the signficant digit counts, as set via
0531: * the API, are ignored.
0532: *
0533: * </ul>
0534: *
0535: * <h4>
0536: * <strong><font face=helvetica color=red>NEW</font></strong>
0537: * Padding</h4>
0538: *
0539: * <p><code>DecimalFormat</code> supports padding the result of
0540: * {@link #format} to a specific width. Padding may be specified either
0541: * through the API or through the pattern syntax. In a pattern the pad escape
0542: * character, followed by a single pad character, causes padding to be parsed
0543: * and formatted. The pad escape character is '*' in unlocalized patterns, and
0544: * can be localized using {@link DecimalFormatSymbols#setPadEscape}. For
0545: * example, <code>"$*x#,##0.00"</code> formats 123 to <code>"$xx123.00"</code>,
0546: * and 1234 to <code>"$1,234.00"</code>.
0547: *
0548: * <ul>
0549: * <li>When padding is in effect, the width of the positive subpattern,
0550: * including prefix and suffix, determines the format width. For example, in
0551: * the pattern <code>"* #0 o''clock"</code>, the format width is 10.
0552: *
0553: * <li>The width is counted in 16-bit code units (Java <code>char</code>s).
0554: *
0555: * <li>Some parameters which usually do not matter have meaning when padding is
0556: * used, because the pattern width is significant with padding. In the pattern
0557: * "* ##,##,#,##0.##", the format width is 14. The initial characters "##,##,"
0558: * do not affect the grouping size or maximum integer digits, but they do affect
0559: * the format width.
0560: *
0561: * <li>Padding may be inserted at one of four locations: before the prefix,
0562: * after the prefix, before the suffix, or after the suffix. If padding is
0563: * specified in any other location, {@link #applyPattern} throws an {@link
0564: * IllegalArgumentException}. If there is no prefix, before the
0565: * prefix and after the prefix are equivalent, likewise for the suffix.
0566: *
0567: * <li>When specified in a pattern, the 16-bit <code>char</code> immediately
0568: * following the pad escape is the pad character. This may be any character,
0569: * including a special pattern character. That is, the pad escape
0570: * <em>escapes</em> the following character. If there is no character after
0571: * the pad escape, then the pattern is illegal.
0572: *
0573: * </ul>
0574: *
0575: * <p>
0576: * <strong><font face=helvetica color=red>NEW</font></strong>
0577: * <strong>Rounding</strong>
0578: *
0579: * <p><code>DecimalFormat</code> supports rounding to a specific increment. For
0580: * example, 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the
0581: * nearest 0.65 is 1.3. The rounding increment may be specified through the API
0582: * or in a pattern. To specify a rounding increment in a pattern, include the
0583: * increment in the pattern itself. "#,#50" specifies a rounding increment of
0584: * 50. "#,##0.05" specifies a rounding increment of 0.05.
0585: *
0586: * <ul>
0587: * <li>Rounding only affects the string produced by formatting. It does
0588: * not affect parsing or change any numerical values.
0589: *
0590: * <li>A <em>rounding mode</em> determines how values are rounded; see the
0591: * {@link com.ibm.icu.math.BigDecimal} documentation for a description of the
0592: * modes. Rounding increments specified in patterns use the default mode,
0593: * {@link com.ibm.icu.math.BigDecimal#ROUND_HALF_EVEN}.
0594: *
0595: * <li>Some locales use rounding in their currency formats to reflect the
0596: * smallest currency denomination.
0597: *
0598: * <li>In a pattern, digits '1' through '9' specify rounding, but otherwise
0599: * behave identically to digit '0'.
0600: * </ul>
0601: *
0602: * <h4>Synchronization</h4>
0603: *
0604: * <p><code>DecimalFormat</code> objects are not synchronized. Multiple
0605: * threads should not access one formatter concurrently.
0606: *
0607: * @see java.text.Format
0608: * @see NumberFormat
0609: * @author Mark Davis
0610: * @author Alan Liu
0611: * @stable ICU 2.0
0612: */
0613: public class DecimalFormat extends NumberFormat {
0614:
0615: /**
0616: * Create a DecimalFormat using the default pattern and symbols
0617: * for the default locale. This is a convenient way to obtain a
0618: * DecimalFormat when internationalization is not the main concern.
0619: * <p>
0620: * To obtain standard formats for a given locale, use the factory methods
0621: * on NumberFormat such as getNumberInstance. These factories will
0622: * return the most appropriate sub-class of NumberFormat for a given
0623: * locale.
0624: * @see NumberFormat#getInstance
0625: * @see NumberFormat#getNumberInstance
0626: * @see NumberFormat#getCurrencyInstance
0627: * @see NumberFormat#getPercentInstance
0628: * @stable ICU 2.0
0629: */
0630: public DecimalFormat() {
0631: // [NEW]
0632: ULocale def = ULocale.getDefault();
0633: String pattern = getPattern(def, 0);
0634: // Always applyPattern after the symbols are set
0635: this .symbols = new DecimalFormatSymbols(def);
0636: setCurrency(Currency.getInstance(def));
0637: applyPattern(pattern, false);
0638: }
0639:
0640: /**
0641: * Create a DecimalFormat from the given pattern and the symbols
0642: * for the default locale. This is a convenient way to obtain a
0643: * DecimalFormat when internationalization is not the main concern.
0644: * <p>
0645: * To obtain standard formats for a given locale, use the factory methods
0646: * on NumberFormat such as getNumberInstance. These factories will
0647: * return the most appropriate sub-class of NumberFormat for a given
0648: * locale.
0649: * @param pattern A non-localized pattern string.
0650: * @exception IllegalArgumentException if the given pattern is invalid.
0651: * @see NumberFormat#getInstance
0652: * @see NumberFormat#getNumberInstance
0653: * @see NumberFormat#getCurrencyInstance
0654: * @see NumberFormat#getPercentInstance
0655: * @stable ICU 2.0
0656: */
0657: public DecimalFormat(String pattern) {
0658: // Always applyPattern after the symbols are set
0659: ULocale def = ULocale.getDefault();
0660: this .symbols = new DecimalFormatSymbols(def);
0661: setCurrency(Currency.getInstance(def));
0662: applyPattern(pattern, false);
0663: }
0664:
0665: /**
0666: * Create a DecimalFormat from the given pattern and symbols.
0667: * Use this constructor when you need to completely customize the
0668: * behavior of the format.
0669: * <p>
0670: * To obtain standard formats for a given
0671: * locale, use the factory methods on NumberFormat such as
0672: * getInstance or getCurrencyInstance. If you need only minor adjustments
0673: * to a standard format, you can modify the format returned by
0674: * a NumberFormat factory method.
0675: * @param pattern a non-localized pattern string
0676: * @param symbols the set of symbols to be used
0677: * @exception IllegalArgumentException if the given pattern is invalid
0678: * @see NumberFormat#getInstance
0679: * @see NumberFormat#getNumberInstance
0680: * @see NumberFormat#getCurrencyInstance
0681: * @see NumberFormat#getPercentInstance
0682: * @see DecimalFormatSymbols
0683: * @stable ICU 2.0
0684: */
0685: public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
0686: // Always applyPattern after the symbols are set
0687: this .symbols = (DecimalFormatSymbols) symbols.clone();
0688: setCurrencyForSymbols();
0689: applyPattern(pattern, false);
0690: }
0691:
0692: /**
0693: * @stable ICU 2.0
0694: */
0695: public StringBuffer format(double number, StringBuffer result,
0696: FieldPosition fieldPosition) {
0697: return format(number, result, fieldPosition, false);
0698: }
0699:
0700: // [Spark/CDL] The actual method to format number. If boolean value
0701: // parseAttr == true, then attribute information will be recorded.
0702: private StringBuffer format(double number, StringBuffer result,
0703: FieldPosition fieldPosition, boolean parseAttr) {
0704: fieldPosition.setBeginIndex(0);
0705: fieldPosition.setEndIndex(0);
0706:
0707: if (Double.isNaN(number)) {
0708: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
0709: fieldPosition.setBeginIndex(result.length());
0710: }
0711:
0712: result.append(symbols.getNaN());
0713: // [Spark/CDL] Add attribute for NaN here.
0714: // result.append(symbols.getNaN());
0715: //#ifndef FOUNDATION
0716: if (parseAttr) {
0717: addAttribute(Field.INTEGER, result.length()
0718: - symbols.getNaN().length(), result.length());
0719: }
0720: //#endif
0721: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
0722: fieldPosition.setEndIndex(result.length());
0723: }
0724:
0725: addPadding(result, fieldPosition, 0, 0);
0726: return result;
0727: }
0728:
0729: /* Detecting whether a double is negative is easy with the exception of
0730: * the value -0.0. This is a double which has a zero mantissa (and
0731: * exponent), but a negative sign bit. It is semantically distinct from
0732: * a zero with a positive sign bit, and this distinction is important
0733: * to certain kinds of computations. However, it's a little tricky to
0734: * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
0735: * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
0736: * -Infinity. Proper detection of -0.0 is needed to deal with the
0737: * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
0738: */
0739: boolean isNegative = (number < 0.0)
0740: || (number == 0.0 && 1 / number < 0.0);
0741: if (isNegative)
0742: number = -number;
0743:
0744: // Do this BEFORE checking to see if value is infinite!
0745: if (multiplier != 1)
0746: number *= multiplier;
0747:
0748: // Apply rounding after multiplier
0749: if (roundingDouble > 0.0) {
0750: // number = roundingDouble
0751: // * round(number / roundingDouble, roundingMode, isNegative);
0752: double newNumber = round(number, roundingDouble,
0753: roundingDoubleReciprocal, roundingMode, isNegative);
0754: if (newNumber == 0.0 && number != newNumber)
0755: isNegative = false; // if we touched it, then make zero be zero.
0756: number = newNumber;
0757: }
0758:
0759: if (Double.isInfinite(number)) {
0760: int prefixLen = appendAffix(result, isNegative, true,
0761: parseAttr);
0762:
0763: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
0764: fieldPosition.setBeginIndex(result.length());
0765: }
0766:
0767: // [Spark/CDL] Add attribute for infinity here.
0768: result.append(symbols.getInfinity());
0769: //#ifndef FOUNDATION
0770: if (parseAttr) {
0771: addAttribute(Field.INTEGER, result.length()
0772: - symbols.getInfinity().length(), result
0773: .length());
0774: }
0775: //#endif
0776: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
0777: fieldPosition.setEndIndex(result.length());
0778: }
0779:
0780: int suffixLen = appendAffix(result, isNegative, false,
0781: parseAttr);
0782:
0783: addPadding(result, fieldPosition, prefixLen, suffixLen);
0784: return result;
0785: }
0786:
0787: // At this point we are guaranteed a nonnegative finite
0788: // number.
0789: synchronized (digitList) {
0790: digitList.set(number, precision(false),
0791: !useExponentialNotation
0792: && !areSignificantDigitsUsed());
0793: return subformat(result, fieldPosition, isNegative, false,
0794: parseAttr);
0795: }
0796: }
0797:
0798: /**
0799: * <strong><font face=helvetica color=red>NEW</font></strong>
0800: * Round a double value to the nearest multiple of the given
0801: * rounding increment, according to the given mode. This is
0802: * equivalent to rounding value/roundingInc to the nearest
0803: * integer, according to the given mode, and returning that
0804: * integer * roundingInc.
0805: * Note this is changed from the version in 2.4, since division of doubles
0806: * have inaccuracies. jitterbug 1871.
0807: * @param number the absolute value of the number to be rounded
0808: * @param roundingInc the rounding increment
0809: * @param roundingIncReciprocal if non-zero, is the
0810: * @param mode a BigDecimal rounding mode
0811: * @param isNegative true if the number to be rounded is negative
0812: * @return the absolute value of the rounded result
0813: */
0814: private static double round(double number, double roundingInc,
0815: double roundingIncReciprocal, int mode, boolean isNegative) {
0816:
0817: double div = roundingIncReciprocal == 0.0 ? number
0818: / roundingInc : number * roundingIncReciprocal;
0819:
0820: // do the absolute cases first
0821:
0822: switch (mode) {
0823: case BigDecimal.ROUND_CEILING:
0824: div = (isNegative ? Math.floor(div + epsilon) : Math
0825: .ceil(div - epsilon));
0826: break;
0827: case BigDecimal.ROUND_FLOOR:
0828: div = (isNegative ? Math.ceil(div - epsilon) : Math
0829: .floor(div + epsilon));
0830: break;
0831: case BigDecimal.ROUND_DOWN:
0832: div = (Math.floor(div + epsilon));
0833: break;
0834: case BigDecimal.ROUND_UP:
0835: div = (Math.ceil(div - epsilon));
0836: break;
0837: case BigDecimal.ROUND_UNNECESSARY:
0838: if (div != Math.floor(div)) {
0839: throw new ArithmeticException("Rounding necessary");
0840: }
0841: return number;
0842: default:
0843:
0844: // Handle complex cases, where the choice depends on the closer value.
0845:
0846: // We figure out the distances to the two possible values, ceiling and floor.
0847: // We then go for the diff that is smaller.
0848: // Only if they are equal does the mode matter.
0849:
0850: double ceil = Math.ceil(div);
0851: double ceildiff = ceil - div; // (ceil * roundingInc) - number;
0852: double floor = Math.floor(div);
0853: double floordiff = div - floor; // number - (floor * roundingInc);
0854:
0855: // Note that the diff values were those mapped back to the "normal" space
0856: // by using the roundingInc. I don't have access to the original author of the code
0857: // but suspect that that was to produce better result in edge cases because of machine
0858: // precision, rather than simply using the difference between, say, ceil and div.
0859: // However, it didn't work in all cases. Am trying instead using an epsilon value.
0860:
0861: switch (mode) {
0862: case BigDecimal.ROUND_HALF_EVEN:
0863: // We should be able to just return Math.rint(a), but this
0864: // doesn't work in some VMs.
0865: // if one is smaller than the other, take the corresponding side
0866: if (floordiff + epsilon < ceildiff) {
0867: div = floor;
0868: } else if (ceildiff + epsilon < floordiff) {
0869: div = ceil;
0870: } else { // they are equal, so we want to round to whichever is even
0871: double testFloor = floor / 2;
0872: div = (testFloor == Math.floor(testFloor)) ? floor
0873: : ceil;
0874: }
0875: break;
0876: case BigDecimal.ROUND_HALF_DOWN:
0877: div = ((floordiff <= ceildiff + epsilon) ? floor : ceil);
0878: break;
0879: case BigDecimal.ROUND_HALF_UP:
0880: div = ((ceildiff <= floordiff + epsilon) ? ceil : floor);
0881: break;
0882: default:
0883: throw new IllegalArgumentException(
0884: "Invalid rounding mode: " + mode);
0885: }
0886: }
0887: number = roundingIncReciprocal == 0.0 ? div * roundingInc : div
0888: / roundingIncReciprocal;
0889: return number;
0890: }
0891:
0892: private static double epsilon = 0.00000000001;
0893:
0894: /**
0895: * @stable ICU 2.0
0896: */
0897: // [Spark/CDL] Delegate to format_long_StringBuffer_FieldPosition_boolean
0898: public StringBuffer format(long number, StringBuffer result,
0899: FieldPosition fieldPosition) {
0900: return format(number, result, fieldPosition, false);
0901: }
0902:
0903: private StringBuffer format(long number, StringBuffer result,
0904: FieldPosition fieldPosition, boolean parseAttr) {
0905: fieldPosition.setBeginIndex(0);
0906: fieldPosition.setEndIndex(0);
0907:
0908: // If we are to do rounding, we need to move into the BigDecimal
0909: // domain in order to do divide/multiply correctly.
0910: // [NEW]
0911: if (roundingIncrementICU != null) {
0912: return format(BigDecimal.valueOf(number), result,
0913: fieldPosition);
0914: }
0915:
0916: boolean isNegative = (number < 0);
0917: if (isNegative)
0918: number = -number;
0919:
0920: // In general, long values always represent real finite numbers, so
0921: // we don't have to check for +/- Infinity or NaN. However, there
0922: // is one case we have to be careful of: The multiplier can push
0923: // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
0924: // check for this before multiplying, and if it happens we use BigInteger
0925: // instead.
0926: // [NEW]
0927: if (multiplier != 1) {
0928: boolean tooBig = false;
0929: if (number < 0) { // This can only happen if number == Long.MIN_VALUE
0930: long cutoff = Long.MIN_VALUE / multiplier;
0931: tooBig = (number < cutoff);
0932: } else {
0933: long cutoff = Long.MAX_VALUE / multiplier;
0934: tooBig = (number > cutoff);
0935: }
0936: if (tooBig) {
0937: // [Spark/CDL] Use
0938: // format_BigInteger_StringBuffer_FieldPosition_boolean instead
0939: // parseAttr is used to judge whether to synthesize attributes.
0940: return format(BigInteger.valueOf(isNegative ? -number
0941: : number), result, fieldPosition, parseAttr);
0942: }
0943: }
0944:
0945: number *= multiplier;
0946: synchronized (digitList) {
0947: digitList.set(number, precision(true));
0948: return subformat(result, fieldPosition, isNegative, true,
0949: parseAttr);
0950: }
0951: }
0952:
0953: /**
0954: * <strong><font face=helvetica color=red>NEW</font></strong> Format a
0955: * BigInteger number.
0956: *
0957: * @stable ICU 2.0
0958: */
0959: public StringBuffer format(BigInteger number, StringBuffer result,
0960: FieldPosition fieldPosition) {
0961: return format(number, result, fieldPosition, false);
0962: }
0963:
0964: // [Spark/CDL]
0965: private StringBuffer format(BigInteger number, StringBuffer result,
0966: FieldPosition fieldPosition, boolean parseAttr) {
0967: // If we are to do rounding, we need to move into the BigDecimal
0968: // domain in order to do divide/multiply correctly.
0969: if (roundingIncrementICU != null) {
0970: return format(new BigDecimal(number), result, fieldPosition);
0971: }
0972:
0973: if (multiplier != 1) {
0974: number = number.multiply(BigInteger.valueOf(multiplier));
0975: }
0976:
0977: // At this point we are guaranteed a nonnegative finite
0978: // number.
0979: synchronized (digitList) {
0980: digitList.set(number, precision(true));
0981: return subformat(result, fieldPosition,
0982: number.signum() < 0, false, parseAttr);
0983: }
0984: }
0985:
0986: //#ifndef FOUNDATION
0987: /**
0988: * <strong><font face=helvetica color=red>NEW</font></strong>
0989: * Format a BigDecimal number.
0990: * @stable ICU 2.0
0991: */
0992: public StringBuffer format(java.math.BigDecimal number,
0993: StringBuffer result, FieldPosition fieldPosition) {
0994: return format(number, result, fieldPosition, false);
0995: }
0996:
0997: private StringBuffer format(java.math.BigDecimal number,
0998: StringBuffer result, FieldPosition fieldPosition,
0999: boolean parseAttr) {
1000: if (multiplier != 1) {
1001: number = number.multiply(java.math.BigDecimal
1002: .valueOf(multiplier));
1003: }
1004:
1005: if (roundingIncrement != null) {
1006: number = number.divide(roundingIncrement, 0, roundingMode)
1007: .multiply(roundingIncrement);
1008: }
1009:
1010: synchronized (digitList) {
1011: digitList.set(number, precision(false),
1012: !useExponentialNotation
1013: && !areSignificantDigitsUsed());
1014: return subformat(result, fieldPosition,
1015: number.signum() < 0, false, parseAttr);
1016: }
1017: }
1018:
1019: //#endif
1020:
1021: /**
1022: * <strong><font face=helvetica color=red>NEW</font></strong>
1023: * Format a BigDecimal number.
1024: * @stable ICU 2.0
1025: */
1026: public StringBuffer format(BigDecimal number, StringBuffer result,
1027: FieldPosition fieldPosition) {
1028: /* This method is just a copy of the corresponding java.math.BigDecimal
1029: * method for now. It isn't very efficient since it must create a
1030: * conversion object to do math on the rounding increment. In the
1031: * future we may try to clean this up, or even better, limit our support
1032: * to just one flavor of BigDecimal.
1033: */
1034: if (multiplier != 1) {
1035: number = number.multiply(BigDecimal.valueOf(multiplier));
1036: }
1037:
1038: if (roundingIncrementICU != null) {
1039: number = number.divide(roundingIncrementICU, 0,
1040: roundingMode).multiply(roundingIncrementICU);
1041: }
1042:
1043: synchronized (digitList) {
1044: digitList.set(number, precision(false),
1045: !useExponentialNotation
1046: && !areSignificantDigitsUsed());
1047: return subformat(result, fieldPosition,
1048: number.signum() < 0, false);
1049: }
1050: }
1051:
1052: /**
1053: * Return true if a grouping separator belongs at the given
1054: * position, based on whether grouping is in use and the values of
1055: * the primary and secondary grouping interval.
1056: * @param pos the number of integer digits to the right of
1057: * the current position. Zero indicates the position after the
1058: * rightmost integer digit.
1059: * @return true if a grouping character belongs at the current
1060: * position.
1061: */
1062: private boolean isGroupingPosition(int pos) {
1063: boolean result = false;
1064: if (isGroupingUsed() && (pos > 0) && (groupingSize > 0)) {
1065: if ((groupingSize2 > 0) && (pos > groupingSize)) {
1066: result = ((pos - groupingSize) % groupingSize2) == 0;
1067: } else {
1068: result = pos % groupingSize == 0;
1069: }
1070: }
1071: return result;
1072: }
1073:
1074: /**
1075: * Return the number of fraction digits to display, or the total
1076: * number of digits for significant digit formats and exponential
1077: * formats.
1078: */
1079: private int precision(boolean isIntegral) {
1080: if (areSignificantDigitsUsed()) {
1081: return getMaximumSignificantDigits();
1082: } else if (useExponentialNotation) {
1083: return getMinimumIntegerDigits()
1084: + getMaximumFractionDigits();
1085: } else {
1086: return isIntegral ? 0 : getMaximumFractionDigits();
1087: }
1088: }
1089:
1090: /**
1091: * Complete the formatting of a finite number. On entry, the digitList must
1092: * be filled in with the correct digits.
1093: */
1094: private StringBuffer subformat(StringBuffer result,
1095: FieldPosition fieldPosition, boolean isNegative,
1096: boolean isInteger) {
1097: return subformat(result, fieldPosition, isNegative, isInteger,
1098: false);
1099: }
1100:
1101: private StringBuffer subformat(StringBuffer result,
1102: FieldPosition fieldPosition, boolean isNegative,
1103: boolean isInteger, boolean parseAttr) {
1104: // NOTE: This isn't required anymore because DigitList takes care of this.
1105: //
1106: // // The negative of the exponent represents the number of leading
1107: // // zeros between the decimal and the first non-zero digit, for
1108: // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
1109: // // is more than the maximum fraction digits, then we have an underflow
1110: // // for the printed representation. We recognize this here and set
1111: // // the DigitList representation to zero in this situation.
1112: //
1113: // if (-digitList.decimalAt >= getMaximumFractionDigits())
1114: // {
1115: // digitList.count = 0;
1116: // }
1117:
1118: int i;
1119: char zero = symbols.getZeroDigit();
1120: int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
1121: char grouping = isCurrencyFormat ? symbols
1122: .getMonetaryGroupingSeparator() : symbols
1123: .getGroupingSeparator();
1124: char decimal = isCurrencyFormat ? symbols
1125: .getMonetaryDecimalSeparator() : symbols
1126: .getDecimalSeparator();
1127: boolean useSigDig = areSignificantDigitsUsed();
1128: int maxIntDig = getMaximumIntegerDigits();
1129: int minIntDig = getMinimumIntegerDigits();
1130:
1131: /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
1132: * format as zero. This allows sensible computations and preserves
1133: * relations such as signum(1/x) = signum(x), where x is +Infinity or
1134: * -Infinity. Prior to this fix, we always formatted zero values as if
1135: * they were positive. Liu 7/6/98.
1136: */
1137: if (digitList.isZero()) {
1138: digitList.decimalAt = 0; // Normalize
1139: }
1140:
1141: int prefixLen = appendAffix(result, isNegative, true, parseAttr);
1142:
1143: if (useExponentialNotation) {
1144: // Record field information for caller.
1145: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1146: fieldPosition.setBeginIndex(result.length());
1147: fieldPosition.setEndIndex(-1);
1148: } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1149: fieldPosition.setBeginIndex(-1);
1150: }
1151:
1152: // [Spark/CDL]
1153: // the begin index of integer part
1154: // the end index of integer part
1155: // the begin index of fractional part
1156: int intBegin = result.length();
1157: int intEnd = -1;
1158: int fracBegin = -1;
1159:
1160: int minFracDig = 0;
1161: if (useSigDig) {
1162: maxIntDig = minIntDig = 1;
1163: minFracDig = getMinimumSignificantDigits() - 1;
1164: } else {
1165: minFracDig = getMinimumFractionDigits();
1166: if (maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
1167: maxIntDig = 1;
1168: if (maxIntDig < minIntDig) {
1169: maxIntDig = minIntDig;
1170: }
1171: }
1172: if (maxIntDig > minIntDig) {
1173: minIntDig = 1;
1174: }
1175: }
1176:
1177: // Minimum integer digits are handled in exponential format by
1178: // adjusting the exponent. For example, 0.01234 with 3 minimum
1179: // integer digits is "123.4E-4".
1180:
1181: // Maximum integer digits are interpreted as indicating the
1182: // repeating range. This is useful for engineering notation, in
1183: // which the exponent is restricted to a multiple of 3. For
1184: // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
1185: // If maximum integer digits are defined and are larger than
1186: // minimum integer digits, then minimum integer digits are
1187: // ignored.
1188:
1189: int exponent = digitList.decimalAt;
1190: if (maxIntDig > 1 && maxIntDig != minIntDig) {
1191: // A exponent increment is defined; adjust to it.
1192: exponent = (exponent > 0) ? (exponent - 1) / maxIntDig
1193: : (exponent / maxIntDig) - 1;
1194: exponent *= maxIntDig;
1195: } else {
1196: // No exponent increment is defined; use minimum integer digits.
1197: // If none is specified, as in "#E0", generate 1 integer digit.
1198: exponent -= (minIntDig > 0 || minFracDig > 0) ? minIntDig
1199: : 1;
1200: }
1201:
1202: // We now output a minimum number of digits, and more if there
1203: // are more digits, up to the maximum number of digits. We
1204: // place the decimal point after the "integer" digits, which
1205: // are the first (decimalAt - exponent) digits.
1206: int minimumDigits = minIntDig + minFracDig;
1207: // The number of integer digits is handled specially if the number
1208: // is zero, since then there may be no digits.
1209: int integerDigits = digitList.isZero() ? minIntDig
1210: : digitList.decimalAt - exponent;
1211: int totalDigits = digitList.count;
1212: if (minimumDigits > totalDigits)
1213: totalDigits = minimumDigits;
1214: if (integerDigits > totalDigits)
1215: totalDigits = integerDigits;
1216:
1217: for (i = 0; i < totalDigits; ++i) {
1218: if (i == integerDigits) {
1219: // Record field information for caller.
1220: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1221: fieldPosition.setEndIndex(result.length());
1222: }
1223: //#ifndef FOUNDATION
1224: // [Spark/CDL] Add attribute for integer part
1225: if (parseAttr) {
1226: intEnd = result.length();
1227: addAttribute(Field.INTEGER, intBegin, result
1228: .length());
1229: }
1230: //#endif
1231: result.append(decimal);
1232: //#ifndef FOUNDATION
1233: // [Spark/CDL] Add attribute for decimal separator
1234: if (parseAttr) {
1235: // Length of decimal separator is 1.
1236: int decimalSeparatorBegin = result.length() - 1;
1237: addAttribute(Field.DECIMAL_SEPARATOR,
1238: decimalSeparatorBegin, result.length());
1239: fracBegin = result.length();
1240: }
1241: //#endif
1242: // Record field information for caller.
1243: if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1244: fieldPosition.setBeginIndex(result.length());
1245: }
1246: }
1247: result
1248: .append((i < digitList.count) ? (char) (digitList.digits[i] + zeroDelta)
1249: : zero);
1250: }
1251:
1252: //For ICU compatibility and format 0 to 0E0 with pattern "#E0" [Richard/GCL]
1253: if (digitList.isZero() && (totalDigits == 0)) {
1254: result.append(zero);
1255: }
1256:
1257: // Record field information
1258: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1259: if (fieldPosition.getEndIndex() < 0) {
1260: fieldPosition.setEndIndex(result.length());
1261: }
1262: } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1263: if (fieldPosition.getBeginIndex() < 0) {
1264: fieldPosition.setBeginIndex(result.length());
1265: }
1266: fieldPosition.setEndIndex(result.length());
1267: }
1268: //#ifndef FOUNDATION
1269: // [Spark/CDL] Calcuate the end index of integer part and fractional
1270: // part if they are not properly processed yet.
1271: if (parseAttr) {
1272: if (intEnd < 0) {
1273: addAttribute(Field.INTEGER, intBegin, result
1274: .length());
1275: }
1276: if (fracBegin > 0) {
1277: addAttribute(Field.FRACTION, fracBegin, result
1278: .length());
1279: }
1280: }
1281: //#endif
1282:
1283: // The exponent is output using the pattern-specified minimum
1284: // exponent digits. There is no maximum limit to the exponent
1285: // digits, since truncating the exponent would result in an
1286: // unacceptable inaccuracy.
1287: result.append(symbols.getExponentSeparator());
1288: //#ifndef FOUNDATION
1289: // [Spark/CDL] For exponent symbol, add an attribute.
1290: if (parseAttr) {
1291: addAttribute(Field.EXPONENT_SYMBOL, result.length()
1292: - symbols.getExponentSeparator().length(),
1293: result.length());
1294: }
1295: //#endif
1296: // For zero values, we force the exponent to zero. We
1297: // must do this here, and not earlier, because the value
1298: // is used to determine integer digit count above.
1299: if (digitList.isZero())
1300: exponent = 0;
1301:
1302: boolean negativeExponent = exponent < 0;
1303: if (negativeExponent) {
1304: exponent = -exponent;
1305: result.append(symbols.getMinusSign());
1306: //#ifndef FOUNDATION
1307: // [Spark/CDL] If exponent has sign, then add an exponent sign
1308: // attribute.
1309: if (parseAttr) {
1310: // Length of exponent sign is 1.
1311: addAttribute(Field.EXPONENT_SIGN,
1312: result.length() - 1, result.length());
1313: }
1314: //#endif
1315: } else if (exponentSignAlwaysShown) {
1316: result.append(symbols.getPlusSign());
1317: //#ifndef FOUNDATION
1318: // [Spark/CDL] Add an plus sign attribute.
1319: if (parseAttr) {
1320: // Length of exponent sign is 1.
1321: int expSignBegin = result.length() - 1;
1322: addAttribute(Field.EXPONENT_SIGN, expSignBegin,
1323: result.length());
1324: }
1325: //#endif
1326: }
1327: int expBegin = result.length();
1328: digitList.set(exponent);
1329: {
1330: int expDig = minExponentDigits;
1331: if (useExponentialNotation && expDig < 1) {
1332: expDig = 1;
1333: }
1334: for (i = digitList.decimalAt; i < expDig; ++i)
1335: result.append(zero);
1336: }
1337: for (i = 0; i < digitList.decimalAt; ++i) {
1338: result
1339: .append((i < digitList.count) ? (char) (digitList.digits[i] + zeroDelta)
1340: : zero);
1341: }
1342: //#ifndef FOUNDATION
1343: // [Spark/CDL] Add attribute for exponent part.
1344: if (parseAttr) {
1345: addAttribute(Field.EXPONENT, expBegin, result.length());
1346: }
1347: //#endif
1348: } else {
1349: // [Spark/CDL] Record the integer start index.
1350: int intBegin = result.length();
1351: // Record field information for caller.
1352: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1353: fieldPosition.setBeginIndex(result.length());
1354: }
1355:
1356: int sigCount = 0;
1357: int minSigDig = getMinimumSignificantDigits();
1358: int maxSigDig = getMaximumSignificantDigits();
1359: if (!useSigDig) {
1360: minSigDig = 0;
1361: maxSigDig = Integer.MAX_VALUE;
1362: }
1363:
1364: // Output the integer portion. Here 'count' is the total
1365: // number of integer digits we will display, including both
1366: // leading zeros required to satisfy getMinimumIntegerDigits,
1367: // and actual digits present in the number.
1368: int count = useSigDig ? Math.max(1, digitList.decimalAt)
1369: : minIntDig;
1370: if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
1371: count = digitList.decimalAt;
1372: }
1373:
1374: // Handle the case where getMaximumIntegerDigits() is smaller
1375: // than the real number of integer digits. If this is so, we
1376: // output the least significant max integer digits. For example,
1377: // the value 1997 printed with 2 max integer digits is just "97".
1378:
1379: int digitIndex = 0; // Index into digitList.fDigits[]
1380: if (count > maxIntDig && maxIntDig >= 0) {
1381: count = maxIntDig;
1382: digitIndex = digitList.decimalAt - count;
1383: }
1384:
1385: int sizeBeforeIntegerPart = result.length();
1386: for (i = count - 1; i >= 0; --i) {
1387: if (i < digitList.decimalAt
1388: && digitIndex < digitList.count
1389: && sigCount < maxSigDig) {
1390: // Output a real digit
1391: byte d = digitList.digits[digitIndex++];
1392: result.append((char) (d + zeroDelta));
1393: ++sigCount;
1394: } else {
1395: // Output a zero (leading or trailing)
1396: result.append(zero);
1397: if (sigCount > 0) {
1398: ++sigCount;
1399: }
1400: }
1401:
1402: // Output grouping separator if necessary.
1403: if (isGroupingPosition(i)) {
1404: result.append(grouping);
1405: //#ifndef FOUNDATION
1406: // [Spark/CDL] Add grouping separator attribute here.
1407: if (parseAttr) {
1408: // Length of grouping separator is 1.
1409: addAttribute(Field.GROUPING_SEPARATOR, result
1410: .length() - 1, result.length());
1411: }
1412: //#endif
1413: }
1414: }
1415:
1416: // Record field information for caller.
1417: if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1418: fieldPosition.setEndIndex(result.length());
1419: }
1420:
1421: // Determine whether or not there are any printable fractional
1422: // digits. If we've used up the digits we know there aren't.
1423: boolean fractionPresent = (!isInteger && digitIndex < digitList.count)
1424: || (useSigDig ? (sigCount < minSigDig)
1425: : (getMinimumFractionDigits() > 0));
1426:
1427: // If there is no fraction present, and we haven't printed any
1428: // integer digits, then print a zero. Otherwise we won't print
1429: // _any_ digits, and we won't be able to parse this string.
1430: if (!fractionPresent
1431: && result.length() == sizeBeforeIntegerPart)
1432: result.append(zero);
1433: //#ifndef FOUNDATION
1434: // [Spark/CDL] Add attribute for integer part.
1435: if (parseAttr) {
1436: addAttribute(Field.INTEGER, intBegin, result.length());
1437: }
1438: //#endif
1439: // Output the decimal separator if we always do so.
1440: if (decimalSeparatorAlwaysShown || fractionPresent) {
1441: result.append(decimal);
1442: //#ifndef FOUNDATION
1443: // [Spark/CDL] Add attribute for decimal separator
1444: if (parseAttr) {
1445: addAttribute(Field.DECIMAL_SEPARATOR, result
1446: .length() - 1, result.length());
1447: }
1448: //#endif
1449: }
1450:
1451: // Record field information for caller.
1452: if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1453: fieldPosition.setBeginIndex(result.length());
1454: }
1455:
1456: // [Spark/CDL] Record the begin index of fraction part.
1457: int fracBegin = result.length();
1458:
1459: count = useSigDig ? Integer.MAX_VALUE
1460: : getMaximumFractionDigits();
1461: if (useSigDig
1462: && (sigCount == maxSigDig || (sigCount >= minSigDig && digitIndex == digitList.count))) {
1463: count = 0;
1464: }
1465: for (i = 0; i < count; ++i) {
1466: // Here is where we escape from the loop. We escape
1467: // if we've output the maximum fraction digits
1468: // (specified in the for expression above). We also
1469: // stop when we've output the minimum digits and
1470: // either: we have an integer, so there is no
1471: // fractional stuff to display, or we're out of
1472: // significant digits.
1473: if (!useSigDig && i >= getMinimumFractionDigits()
1474: && (isInteger || digitIndex >= digitList.count)) {
1475: break;
1476: }
1477:
1478: // Output leading fractional zeros. These are zeros
1479: // that come after the decimal but before any
1480: // significant digits. These are only output if
1481: // abs(number being formatted) < 1.0.
1482: if (-1 - i > (digitList.decimalAt - 1)) {
1483: result.append(zero);
1484: continue;
1485: }
1486:
1487: // Output a digit, if we have any precision left, or a
1488: // zero if we don't. We don't want to output noise digits.
1489: if (!isInteger && digitIndex < digitList.count) {
1490: result
1491: .append((char) (digitList.digits[digitIndex++] + zeroDelta));
1492: } else {
1493: result.append(zero);
1494: }
1495:
1496: // If we reach the maximum number of significant
1497: // digits, or if we output all the real digits and
1498: // reach the minimum, then we are done.
1499: ++sigCount;
1500: if (useSigDig
1501: && (sigCount == maxSigDig || (digitIndex == digitList.count && sigCount >= minSigDig))) {
1502: break;
1503: }
1504: }
1505:
1506: // Record field information for caller.
1507: if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1508: fieldPosition.setEndIndex(result.length());
1509: }
1510: //#ifndef FOUNDATION
1511: // [Spark/CDL] Add attribute information if necessary.
1512: if (parseAttr
1513: && (decimalSeparatorAlwaysShown || fractionPresent)) {
1514: addAttribute(Field.FRACTION, fracBegin, result.length());
1515: }
1516: //#endif
1517: }
1518:
1519: int suffixLen = appendAffix(result, isNegative, false,
1520: parseAttr);
1521:
1522: // [NEW]
1523: addPadding(result, fieldPosition, prefixLen, suffixLen);
1524: return result;
1525: }
1526:
1527: // [NEW]
1528: private final void addPadding(StringBuffer result,
1529: FieldPosition fieldPosition, int prefixLen, int suffixLen) {
1530: if (formatWidth > 0) {
1531: int len = formatWidth - result.length();
1532: if (len > 0) {
1533: char[] padding = new char[len];
1534: for (int i = 0; i < len; ++i) {
1535: padding[i] = pad;
1536: }
1537: switch (padPosition) {
1538: case PAD_AFTER_PREFIX:
1539: result.insert(prefixLen, padding);
1540: break;
1541: case PAD_BEFORE_PREFIX:
1542: result.insert(0, padding);
1543: break;
1544: case PAD_BEFORE_SUFFIX:
1545: result.insert(result.length() - suffixLen, padding);
1546: break;
1547: case PAD_AFTER_SUFFIX:
1548: result.append(padding);
1549: break;
1550: }
1551: if (padPosition == PAD_BEFORE_PREFIX
1552: || padPosition == PAD_AFTER_PREFIX) {
1553: fieldPosition.setBeginIndex(fieldPosition
1554: .getBeginIndex()
1555: + len);
1556: fieldPosition.setEndIndex(fieldPosition
1557: .getEndIndex()
1558: + len);
1559: }
1560: }
1561: }
1562: }
1563:
1564: /**
1565: * <strong><font face=helvetica color=red>CHANGED</font></strong>
1566: * Parse the given string, returning a <code>Number</code> object to
1567: * represent the parsed value. <code>Double</code> objects are returned to
1568: * represent non-integral values which cannot be stored in a
1569: * <code>BigDecimal</code>. These are <code>NaN</code>, infinity,
1570: * -infinity, and -0.0. If {@link #isParseBigDecimal()} is false (the
1571: * default), all other values are returned as <code>Long</code>,
1572: * <code>BigInteger</code>, or <code>BigDecimal</code> values,
1573: * in that order of preference. If {@link #isParseBigDecimal()} is true,
1574: * all other values are returned as <code>BigDecimal</code> valuse.
1575: * If the parse fails, null is returned.
1576: * @param text the string to be parsed
1577: * @param parsePosition defines the position where parsing is to begin,
1578: * and upon return, the position where parsing left off. If the position
1579: * has not changed upon return, then parsing failed.
1580: * @return a <code>Number</code> object with the parsed value or
1581: * <code>null</code> if the parse failed
1582: * @stable ICU 2.0
1583: */
1584: public Number parse(String text, ParsePosition parsePosition) {
1585: return (Number) parse(text, parsePosition, false);
1586: }
1587:
1588: /**
1589: * <strong><font face=helvetica color=red>NEW</font></strong>
1590: * Parses text from the given string as a CurrencyAmount. Unlike
1591: * the parse() method, this method will attempt to parse a generic
1592: * currency name, searching for a match of this object's locale's
1593: * currency display names, or for a 3-letter ISO currency code.
1594: * This method will fail if this format is not a currency format,
1595: * that is, if it does not contain the currency pattern symbol
1596: * (U+00A4) in its prefix or suffix.
1597: *
1598: * @param text the string to parse
1599: * @param pos input-output position; on input, the position within
1600: * text to match; must have 0 <= pos.getIndex() < text.length();
1601: * on output, the position after the last matched character. If
1602: * the parse fails, the position in unchanged upon output.
1603: * @return a CurrencyAmount, or null upon failure
1604: * @internal
1605: * @deprecated This API is ICU internal only.
1606: */
1607: CurrencyAmount parseCurrency(String text, ParsePosition pos) {
1608: return (CurrencyAmount) parse(text, pos, true);
1609: }
1610:
1611: /**
1612: * Parses the given text as either a Number or a CurrencyAmount.
1613: * @param text the string to parse
1614: * @param parsePosition input-output position; on input, the
1615: * position within text to match; must have 0 <= pos.getIndex() <
1616: * text.length(); on output, the position after the last matched
1617: * character. If the parse fails, the position in unchanged upon
1618: * output.
1619: * @param parseCurrency if true, a CurrencyAmount is parsed and
1620: * returned; otherwise a Number is parsed and returned
1621: * @return a Number or CurrencyAmount or null
1622: */
1623: private Object parse(String text, ParsePosition parsePosition,
1624: boolean parseCurrency) {
1625: int backup;
1626: int i = backup = parsePosition.getIndex();
1627:
1628: // Handle NaN as a special case:
1629:
1630: // Skip padding characters, if around prefix
1631: if (formatWidth > 0
1632: && (padPosition == PAD_BEFORE_PREFIX || padPosition == PAD_AFTER_PREFIX)) {
1633: i = skipPadding(text, i);
1634: }
1635: if (text.regionMatches(i, symbols.getNaN(), 0, symbols.getNaN()
1636: .length())) {
1637: i += symbols.getNaN().length();
1638: // Skip padding characters, if around suffix
1639: if (formatWidth > 0
1640: && (padPosition == PAD_BEFORE_SUFFIX || padPosition == PAD_AFTER_SUFFIX)) {
1641: i = skipPadding(text, i);
1642: }
1643: parsePosition.setIndex(i);
1644: return new Double(Double.NaN);
1645: }
1646:
1647: // NaN parse failed; start over
1648: i = backup;
1649:
1650: boolean[] status = new boolean[STATUS_LENGTH];
1651: Currency[] currency = parseCurrency ? new Currency[1] : null;
1652: if (!subparse(text, parsePosition, digitList, false, status,
1653: currency)) {
1654: parsePosition.setIndex(backup);
1655: return null;
1656: }
1657:
1658: Number n = null;
1659:
1660: // Handle infinity
1661: if (status[STATUS_INFINITE]) {
1662: n = new Double(
1663: status[STATUS_POSITIVE] ? Double.POSITIVE_INFINITY
1664: : Double.NEGATIVE_INFINITY);
1665: }
1666:
1667: // Handle -0.0
1668: else if (!status[STATUS_POSITIVE] && digitList.isZero()) {
1669: n = new Double(-0.0);
1670: }
1671:
1672: else {
1673: // Do as much of the multiplier conversion as possible without
1674: // losing accuracy.
1675: int mult = multiplier; // Don't modify this.multiplier
1676: while (mult % 10 == 0) {
1677: --digitList.decimalAt;
1678: mult /= 10;
1679: }
1680:
1681: // Handle integral values
1682: if (!parseBigDecimal && mult == 1 && digitList.isIntegral()) {
1683: // hack quick long
1684: if (digitList.decimalAt < 12) { // quick check for long
1685: long l = 0;
1686: if (digitList.count > 0) {
1687: int nx = 0;
1688: while (nx < digitList.count) {
1689: l = l * 10 + (char) digitList.digits[nx++]
1690: - '0';
1691: }
1692: while (nx++ < digitList.decimalAt) {
1693: l *= 10;
1694: }
1695: if (!status[STATUS_POSITIVE]) {
1696: l = -l;
1697: }
1698: }
1699: n = new Long(l);
1700: } else {
1701: BigInteger big = digitList
1702: .getBigInteger(status[STATUS_POSITIVE]);
1703: n = (big.bitLength() < 64) ? (Number) new Long(big
1704: .longValue()) : (Number) big;
1705: }
1706: }
1707:
1708: // Handle non-integral values or the case where parseBigDecimal is set
1709: else {
1710: BigDecimal big = digitList
1711: .getBigDecimalICU(status[STATUS_POSITIVE]);
1712: n = big;
1713: if (mult != 1) {
1714: n = big.divide(BigDecimal.valueOf(mult),
1715: BigDecimal.ROUND_HALF_EVEN);
1716: }
1717: }
1718: }
1719:
1720: // Assemble into CurrencyAmount if necessary
1721: return parseCurrency ? (Object) new CurrencyAmount(n,
1722: currency[0]) : (Object) n;
1723: }
1724:
1725: private static final int STATUS_INFINITE = 0;
1726: private static final int STATUS_POSITIVE = 1;
1727: private static final int STATUS_LENGTH = 2;
1728:
1729: /**
1730: * <strong><font face=helvetica color=red>CHANGED</font></strong>
1731: * Parse the given text into a number. The text is parsed beginning at
1732: * parsePosition, until an unparseable character is seen.
1733: * @param text The string to parse.
1734: * @param parsePosition The position at which to being parsing. Upon
1735: * return, the first unparseable character.
1736: * @param digits The DigitList to set to the parsed value.
1737: * @param isExponent If true, parse an exponent. This means no
1738: * infinite values and integer only.
1739: * @param status Upon return contains boolean status flags indicating
1740: * whether the value was infinite and whether it was positive.
1741: * @param currency return value for parsed currency, for generic
1742: * currency parsing mode, or null for normal parsing. In generic
1743: * currency parsing mode, any currency is parsed, not just the
1744: * currency that this formatter is set to.
1745: */
1746: private final boolean subparse(String text,
1747: ParsePosition parsePosition, DigitList digits,
1748: boolean isExponent, boolean status[], Currency currency[]) {
1749: int position = parsePosition.getIndex();
1750: int oldStart = parsePosition.getIndex();
1751:
1752: // Match padding before prefix
1753: if (formatWidth > 0 && padPosition == PAD_BEFORE_PREFIX) {
1754: position = skipPadding(text, position);
1755: }
1756:
1757: // Match positive and negative prefixes; prefer longest match.
1758: int posMatch = compareAffix(text, position, false, true,
1759: currency);
1760: int negMatch = compareAffix(text, position, true, true,
1761: currency);
1762: if (posMatch >= 0 && negMatch >= 0) {
1763: if (posMatch > negMatch) {
1764: negMatch = -1;
1765: } else if (negMatch > posMatch) {
1766: posMatch = -1;
1767: }
1768: }
1769: if (posMatch >= 0) {
1770: position += posMatch;
1771: } else if (negMatch >= 0) {
1772: position += negMatch;
1773: } else {
1774: parsePosition.setErrorIndex(position);
1775: return false;
1776: }
1777:
1778: // Match padding after prefix
1779: if (formatWidth > 0 && padPosition == PAD_AFTER_PREFIX) {
1780: position = skipPadding(text, position);
1781: }
1782:
1783: // process digits or Inf, find decimal position
1784: status[STATUS_INFINITE] = false;
1785: if (!isExponent
1786: && text.regionMatches(position, symbols.getInfinity(),
1787: 0, symbols.getInfinity().length())) {
1788: position += symbols.getInfinity().length();
1789: status[STATUS_INFINITE] = true;
1790: } else {
1791: // We now have a string of digits, possibly with grouping symbols,
1792: // and decimal points. We want to process these into a DigitList.
1793: // We don't want to put a bunch of leading zeros into the DigitList
1794: // though, so we keep track of the location of the decimal point,
1795: // put only significant digits into the DigitList, and adjust the
1796: // exponent as needed.
1797:
1798: digits.decimalAt = digits.count = 0;
1799: char zero = symbols.getZeroDigit();
1800: char decimal = isCurrencyFormat ? symbols
1801: .getMonetaryDecimalSeparator() : symbols
1802: .getDecimalSeparator();
1803: char grouping = symbols.getGroupingSeparator();
1804: String exponentSep = symbols.getExponentSeparator();
1805: boolean sawDecimal = false;
1806: boolean sawExponent = false;
1807: boolean sawDigit = false;
1808: int exponent = 0; // Set to the exponent value, if any
1809: int digit = 0;
1810:
1811: // strict parsing
1812: boolean strictParse = isParseStrict();
1813: boolean strictFail = false; // did we exit with a strict parse failure?
1814: boolean leadingZero = false; // did we see a leading zero?
1815: int lastGroup = -1; // where did we last see a grouping separator?
1816: int prevGroup = -1; // where did we see the grouping separator before that?
1817: int gs2 = groupingSize2 == 0 ? groupingSize : groupingSize2;
1818:
1819: // We have to track digitCount ourselves, because digits.count will
1820: // pin when the maximum allowable digits is reached.
1821: int digitCount = 0;
1822:
1823: int backup = -1;
1824: for (; position < text.length(); ++position) {
1825: char ch = text.charAt(position);
1826:
1827: /* We recognize all digit ranges, not only the Latin digit range
1828: * '0'..'9'. We do so by using the UCharacter.digit() method,
1829: * which converts a valid Unicode digit to the range 0..9.
1830: *
1831: * The character 'ch' may be a digit. If so, place its value
1832: * from 0 to 9 in 'digit'. First try using the locale digit,
1833: * which may or MAY NOT be a standard Unicode digit range. If
1834: * this fails, try using the standard Unicode digit ranges by
1835: * calling UCharacter.digit(). If this also fails, digit will
1836: * have a value outside the range 0..9.
1837: */
1838: digit = ch - zero;
1839: if (digit < 0 || digit > 9)
1840: digit = UCharacter.digit(ch, 10);
1841:
1842: if (digit == 0) {
1843: // Cancel out backup setting (see grouping handler below)
1844: if (strictParse && backup != -1) {
1845: // comma followed by digit, so group before comma is a
1846: // secondary group. If there was a group separator
1847: // before that, the group must == the secondary group
1848: // length, else it can be <= the the secondary group
1849: // length.
1850: if ((lastGroup != -1 && backup - lastGroup - 1 != gs2)
1851: || (lastGroup == -1 && position
1852: - oldStart - 1 > gs2)) {
1853: strictFail = true;
1854: break;
1855: }
1856: prevGroup = lastGroup;
1857: lastGroup = backup;
1858: }
1859: backup = -1; // Do this BEFORE continue statement below!!!
1860: sawDigit = true;
1861:
1862: // Handle leading zeros
1863: if (digits.count == 0) {
1864: if (!sawDecimal) {
1865: if (strictParse && !isExponent) {
1866: // Allow leading zeros in exponents
1867: if (leadingZero) {
1868: strictFail = true;
1869: break;
1870: }
1871: leadingZero = true;
1872: }
1873: // Ignore leading zeros in integer part of number.
1874: continue;
1875: }
1876:
1877: // If we have seen the decimal, but no significant digits yet,
1878: // then we account for leading zeros by decrementing the
1879: // digits.decimalAt into negative values.
1880: --digits.decimalAt;
1881: } else {
1882: ++digitCount;
1883: digits.append((char) (digit + '0'));
1884: }
1885: } else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above
1886: {
1887: if (strictParse) {
1888: if (leadingZero) {
1889: // a leading zero before a digit is an error with strict parsing
1890: strictFail = true;
1891: break;
1892: }
1893: if (backup != -1) {
1894: if ((lastGroup != -1 && backup - lastGroup
1895: - 1 != gs2)
1896: || (lastGroup == -1 && position
1897: - oldStart - 1 > gs2)) {
1898: strictFail = true;
1899: break;
1900: }
1901: prevGroup = lastGroup;
1902: lastGroup = backup;
1903: }
1904: }
1905:
1906: sawDigit = true;
1907: ++digitCount;
1908: digits.append((char) (digit + '0'));
1909:
1910: // Cancel out backup setting (see grouping handler below)
1911: backup = -1;
1912: } else if (!isExponent && ch == decimal) {
1913: if (strictParse) {
1914: if (backup != -1
1915: || (lastGroup != -1 && position
1916: - lastGroup != groupingSize - 1)) {
1917: strictFail = true;
1918: break;
1919: }
1920: }
1921: // If we're only parsing integers, or if we ALREADY saw the
1922: // decimal, then don't parse this one.
1923: if (isParseIntegerOnly() || sawDecimal)
1924: break;
1925: digits.decimalAt = digitCount; // Not digits.count!
1926: sawDecimal = true;
1927: leadingZero = false; // a single leading zero before a decimal is ok
1928: } else if (!isExponent && ch == grouping
1929: && isGroupingUsed()) {
1930: if (sawDecimal) {
1931: break;
1932: }
1933: if (strictParse) {
1934: if ((!sawDigit || backup != -1)) {
1935: // leading group, or two group separators in a row
1936: strictFail = true;
1937: break;
1938: }
1939: }
1940: // Ignore grouping characters, if we are using them, but require
1941: // that they be followed by a digit. Otherwise we backup and
1942: // reprocess them.
1943: backup = position;
1944: } else if (!isExponent
1945: && !sawExponent
1946: && text.regionMatches(position, exponentSep, 0,
1947: exponentSep.length())) {
1948: // Parse sign, if present
1949: boolean negExp = false;
1950: int pos = position + exponentSep.length();
1951: if (pos < text.length()) {
1952: ch = text.charAt(pos);
1953: if (ch == symbols.getPlusSign()) {
1954: ++pos;
1955: } else if (ch == symbols.getMinusSign()) {
1956: ++pos;
1957: negExp = true;
1958: }
1959: }
1960:
1961: DigitList exponentDigits = new DigitList();
1962: exponentDigits.count = 0;
1963: while (pos < text.length()) {
1964: digit = text.charAt(pos) - zero;
1965: if (digit < 0 || digit > 9) {
1966: /*
1967: Can't parse "[1E0]" when pattern is "0.###E0;[0.###E0]"
1968: Should update reassign the value of 'ch' in the
1969: code: digit = Character.digit(ch, 10);
1970: [Richard/GCL]
1971: */
1972: digit = UCharacter.digit(text.charAt(pos),
1973: 10);
1974: }
1975: if (digit >= 0 && digit <= 9) {
1976: exponentDigits.append((char) (digit + '0'));
1977: ++pos;
1978: } else {
1979: break;
1980: }
1981: }
1982:
1983: if (exponentDigits.count > 0) {
1984: // defer strict parse until we know we have a bona-fide exponent
1985: if (strictParse) {
1986: if (backup != -1 || lastGroup != -1) {
1987: strictFail = true;
1988: break;
1989: }
1990: }
1991:
1992: exponentDigits.decimalAt = exponentDigits.count;
1993: exponent = (int) exponentDigits.getLong();
1994: if (negExp) {
1995: exponent = -exponent;
1996: }
1997: position = pos; // Advance past the exponent
1998: sawExponent = true;
1999: }
2000:
2001: break; // Whether we fail or succeed, we exit this loop
2002: } else
2003: break;
2004: }
2005:
2006: if (backup != -1)
2007: position = backup;
2008:
2009: if (strictParse && !sawDecimal) {
2010: if (lastGroup != -1
2011: && position - lastGroup != groupingSize + 1) {
2012: strictFail = true;
2013: }
2014: }
2015: if (strictFail) {
2016: // only set with strictParse and a leading zero error
2017: // leading zeros are an error with strict parsing except
2018: // immediately before nondigit (except group separator
2019: // followed by digit), or end of text.
2020:
2021: parsePosition.setIndex(oldStart);
2022: parsePosition.setErrorIndex(position);
2023: return false;
2024: }
2025:
2026: // If there was no decimal point we have an integer
2027: if (!sawDecimal)
2028: digits.decimalAt = digitCount; // Not digits.count!
2029:
2030: // Adjust for exponent, if any
2031: digits.decimalAt += exponent;
2032:
2033: // If none of the text string was recognized. For example, parse
2034: // "x" with pattern "#0.00" (return index and error index both 0)
2035: // parse "$" with pattern "$#0.00". (return index 0 and error index
2036: // 1).
2037: if (!sawDigit && digitCount == 0) {
2038: parsePosition.setIndex(oldStart);
2039: parsePosition.setErrorIndex(oldStart);
2040: return false;
2041: }
2042: }
2043:
2044: // Match padding before suffix
2045: if (formatWidth > 0 && padPosition == PAD_BEFORE_SUFFIX) {
2046: position = skipPadding(text, position);
2047: }
2048:
2049: // Match positive and negative suffixes; prefer longest match.
2050: if (posMatch >= 0) {
2051: posMatch = compareAffix(text, position, false, false,
2052: currency);
2053: }
2054: if (negMatch >= 0) {
2055: negMatch = compareAffix(text, position, true, false,
2056: currency);
2057: }
2058: if (posMatch >= 0 && negMatch >= 0) {
2059: if (posMatch > negMatch) {
2060: negMatch = -1;
2061: } else if (negMatch > posMatch) {
2062: posMatch = -1;
2063: }
2064: }
2065:
2066: // Fail if neither or both
2067: if ((posMatch >= 0) == (negMatch >= 0)) {
2068: parsePosition.setErrorIndex(position);
2069: return false;
2070: }
2071:
2072: position += (posMatch >= 0 ? posMatch : negMatch);
2073:
2074: // Match padding after suffix
2075: if (formatWidth > 0 && padPosition == PAD_AFTER_SUFFIX) {
2076: position = skipPadding(text, position);
2077: }
2078:
2079: parsePosition.setIndex(position);
2080:
2081: status[STATUS_POSITIVE] = (posMatch >= 0);
2082:
2083: if (parsePosition.getIndex() == oldStart) {
2084: parsePosition.setErrorIndex(position);
2085: return false;
2086: }
2087: return true;
2088: }
2089:
2090: /**
2091: * Starting at position, advance past a run of pad characters, if any.
2092: * Return the index of the first character after position that is not a pad
2093: * character. Result is >= position.
2094: */
2095: private final int skipPadding(String text, int position) {
2096: while (position < text.length() && text.charAt(position) == pad) {
2097: ++position;
2098: }
2099: return position;
2100: }
2101:
2102: /**
2103: * Return the length matched by the given affix, or -1 if none.
2104: * Runs of white space in the affix, match runs of white space in
2105: * the input. Pattern white space and input white space are
2106: * determined differently; see code.
2107: * @param text input text
2108: * @param pos offset into input at which to begin matching
2109: * @param isNegative
2110: * @param isPrefix
2111: * @param currency return value for parsed currency, for generic
2112: * currency parsing mode, or null for normal parsing. In generic
2113: * currency parsing mode, any currency is parsed, not just the
2114: * currency that this formatter is set to.
2115: * @return length of input that matches, or -1 if match failure
2116: */
2117: private int compareAffix(String text, int pos, boolean isNegative,
2118: boolean isPrefix, Currency[] currency) {
2119: if (currency != null || currencyChoice != null) {
2120: if (isPrefix) {
2121: return compareComplexAffix(
2122: isNegative ? negPrefixPattern
2123: : posPrefixPattern, text, pos, currency);
2124: } else {
2125: return compareComplexAffix(
2126: isNegative ? negSuffixPattern
2127: : posSuffixPattern, text, pos, currency);
2128: }
2129: }
2130:
2131: if (isPrefix) {
2132: return compareSimpleAffix(isNegative ? negativePrefix
2133: : positivePrefix, text, pos);
2134: } else {
2135: return compareSimpleAffix(isNegative ? negativeSuffix
2136: : positiveSuffix, text, pos);
2137: }
2138: }
2139:
2140: /**
2141: * Return the length matched by the given affix, or -1 if none.
2142: * Runs of white space in the affix, match runs of white space in
2143: * the input. Pattern white space and input white space are
2144: * determined differently; see code.
2145: * @param affix pattern string, taken as a literal
2146: * @param input input text
2147: * @param pos offset into input at which to begin matching
2148: * @return length of input that matches, or -1 if match failure
2149: */
2150: private static int compareSimpleAffix(String affix, String input,
2151: int pos) {
2152: int start = pos;
2153: for (int i = 0; i < affix.length();) {
2154: int c = UTF16.charAt(affix, i);
2155: int len = UTF16.getCharCount(c);
2156: if (UCharacterProperty.isRuleWhiteSpace(c)) {
2157: // We may have a pattern like: \u200F \u0020
2158: // and input text like: \u200F \u0020
2159: // Note that U+200F and U+0020 are RuleWhiteSpace but only
2160: // U+0020 is UWhiteSpace. So we have to first do a direct
2161: // match of the run of RULE whitespace in the pattern,
2162: // then match any extra characters.
2163: boolean literalMatch = false;
2164: while (pos < input.length()
2165: && UTF16.charAt(input, pos) == c) {
2166: literalMatch = true;
2167: i += len;
2168: pos += len;
2169: if (i == affix.length()) {
2170: break;
2171: }
2172: c = UTF16.charAt(affix, i);
2173: len = UTF16.getCharCount(c);
2174: if (!UCharacterProperty.isRuleWhiteSpace(c)) {
2175: break;
2176: }
2177: }
2178:
2179: // Advance over run in affix
2180: i = skipRuleWhiteSpace(affix, i);
2181:
2182: // Advance over run in input text
2183: // Must see at least one white space char in input,
2184: // unless we've already matched some characters literally.
2185: int s = pos;
2186: pos = skipUWhiteSpace(input, pos);
2187: if (pos == s && !literalMatch) {
2188: return -1;
2189: }
2190: } else {
2191: if (pos < input.length()
2192: && UTF16.charAt(input, pos) == c) {
2193: i += len;
2194: pos += len;
2195: } else {
2196: return -1;
2197: }
2198: }
2199: }
2200: return pos - start;
2201: }
2202:
2203: /**
2204: * Skip over a run of zero or more isRuleWhiteSpace() characters at
2205: * pos in text.
2206: */
2207: private static int skipRuleWhiteSpace(String text, int pos) {
2208: while (pos < text.length()) {
2209: int c = UTF16.charAt(text, pos);
2210: if (!UCharacterProperty.isRuleWhiteSpace(c)) {
2211: break;
2212: }
2213: pos += UTF16.getCharCount(c);
2214: }
2215: return pos;
2216: }
2217:
2218: /**
2219: * Skip over a run of zero or more isUWhiteSpace() characters at pos
2220: * in text.
2221: */
2222: private static int skipUWhiteSpace(String text, int pos) {
2223: while (pos < text.length()) {
2224: int c = UTF16.charAt(text, pos);
2225: if (!UCharacter.isUWhiteSpace(c)) {
2226: break;
2227: }
2228: pos += UTF16.getCharCount(c);
2229: }
2230: return pos;
2231: }
2232:
2233: /**
2234: * Return the length matched by the given affix, or -1 if none.
2235: * @param affixPat pattern string
2236: * @param text input text
2237: * @param pos offset into input at which to begin matching
2238: * @param currency return value for parsed currency, for generic
2239: * currency parsing mode, or null for normal parsing. In generic
2240: * currency parsing mode, any currency is parsed, not just the
2241: * currency that this formatter is set to.
2242: * @return length of input that matches, or -1 if match failure
2243: */
2244: private int compareComplexAffix(String affixPat, String text,
2245: int pos, Currency[] currency) {
2246:
2247: for (int i = 0; i < affixPat.length() && pos >= 0;) {
2248: char c = affixPat.charAt(i++);
2249: if (c == QUOTE) {
2250: for (;;) {
2251: int j = affixPat.indexOf(QUOTE, i);
2252: if (j == i) {
2253: pos = match(text, pos, QUOTE);
2254: i = j + 1;
2255: break;
2256: } else if (j > i) {
2257: pos = match(text, pos, affixPat.substring(i, j));
2258: i = j + 1;
2259: if (i < affixPat.length()
2260: && affixPat.charAt(i) == QUOTE) {
2261: pos = match(text, pos, QUOTE);
2262: ++i;
2263: // loop again
2264: } else {
2265: break;
2266: }
2267: } else {
2268: // Unterminated quote; should be caught by apply
2269: // pattern.
2270: throw new RuntimeException();
2271: }
2272: }
2273: continue;
2274: }
2275:
2276: switch (c) {
2277: case CURRENCY_SIGN:
2278: // If currency != null, then perform generic currency matching.
2279: // Otherwise, do currency choice parsing.
2280: //assert(currency != null ||
2281: // (getCurrency() != null && currencyChoice != null));
2282: boolean intl = i < affixPat.length()
2283: && affixPat.charAt(i) == CURRENCY_SIGN;
2284:
2285: // Parse generic currency -- anything for which we
2286: // have a display name, or any 3-letter ISO code.
2287: if (currency != null) {
2288: // Try to parse display name for our locale; first
2289: // determine our locale.
2290: ULocale uloc = getLocale(ULocale.VALID_LOCALE);
2291: if (uloc == null) {
2292: // applyPattern has been called; use the symbols
2293: uloc = symbols.getLocale(ULocale.VALID_LOCALE);
2294: }
2295: // Delegate parse of display name => ISO code to Currency
2296: ParsePosition ppos = new ParsePosition(pos);
2297: String iso = Currency.parse(uloc, text, ppos);
2298:
2299: // If parse succeeds, populate currency[0]
2300: if (iso != null) {
2301: currency[0] = Currency.getInstance(iso);
2302: pos = ppos.getIndex();
2303: } else {
2304: pos = -1;
2305: }
2306: } else {
2307: if (intl) {
2308: ++i;
2309: pos = match(text, pos, getCurrency()
2310: .getCurrencyCode());
2311: } else {
2312: ParsePosition ppos = new ParsePosition(pos);
2313: /* Number n = */currencyChoice.parse(text,
2314: ppos);
2315: pos = (ppos.getIndex() == pos) ? -1 : ppos
2316: .getIndex();
2317: }
2318: }
2319: continue;
2320: case PATTERN_PERCENT:
2321: c = symbols.getPercent();
2322: break;
2323: case PATTERN_PER_MILLE:
2324: c = symbols.getPerMill();
2325: break;
2326: case PATTERN_MINUS:
2327: c = symbols.getMinusSign();
2328: break;
2329: }
2330: pos = match(text, pos, c);
2331: if (UCharacterProperty.isRuleWhiteSpace(c)) {
2332: i = skipRuleWhiteSpace(affixPat, i);
2333: }
2334: }
2335:
2336: return pos;
2337: }
2338:
2339: /**
2340: * Match a single character at text[pos] and return the index of the
2341: * next character upon success. Return -1 on failure. If
2342: * isRuleWhiteSpace(ch) then match a run of white space in text.
2343: */
2344: static final int match(String text, int pos, int ch) {
2345: if (UCharacterProperty.isRuleWhiteSpace(ch)) {
2346: // Advance over run of white space in input text
2347: // Must see at least one white space char in input
2348: int s = pos;
2349: pos = skipUWhiteSpace(text, pos);
2350: if (pos == s) {
2351: return -1;
2352: }
2353: return pos;
2354: }
2355: return (pos >= 0 && UTF16.charAt(text, pos) == ch) ? (pos + UTF16
2356: .getCharCount(ch))
2357: : -1;
2358: }
2359:
2360: /**
2361: * Match a string at text[pos] and return the index of the next
2362: * character upon success. Return -1 on failure. Match a run of
2363: * white space in str with a run of white space in text.
2364: */
2365: static final int match(String text, int pos, String str) {
2366: for (int i = 0; i < str.length() && pos >= 0;) {
2367: int ch = UTF16.charAt(str, i);
2368: i += UTF16.getCharCount(ch);
2369: pos = match(text, pos, ch);
2370: if (UCharacterProperty.isRuleWhiteSpace(ch)) {
2371: i = skipRuleWhiteSpace(str, i);
2372: }
2373: }
2374: return pos;
2375: }
2376:
2377: /**
2378: * Returns a copy of the decimal format symbols used by this format.
2379: * @return desired DecimalFormatSymbols
2380: * @see DecimalFormatSymbols
2381: * @stable ICU 2.0
2382: */
2383: public DecimalFormatSymbols getDecimalFormatSymbols() {
2384: try {
2385: // don't allow multiple references
2386: return (DecimalFormatSymbols) symbols.clone();
2387: } catch (Exception foo) {
2388: return null; // should never happen
2389: }
2390: }
2391:
2392: /**
2393: * Sets the decimal format symbols used by this format. The
2394: * format uses a copy of the provided symbols.
2395: * @param newSymbols desired DecimalFormatSymbols
2396: * @see DecimalFormatSymbols
2397: * @stable ICU 2.0
2398: */
2399: public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
2400: symbols = (DecimalFormatSymbols) newSymbols.clone();
2401: setCurrencyForSymbols();
2402: expandAffixes();
2403: }
2404:
2405: /**
2406: * Update the currency object to match the symbols. This method
2407: * is used only when the caller has passed in a symbols object
2408: * that may not be the default object for its locale.
2409: */
2410: private void setCurrencyForSymbols() {
2411: /*Bug 4212072
2412: Update the affix strings accroding to symbols in order to keep
2413: the affix strings up to date.
2414: [Richard/GCL]
2415: */
2416:
2417: // With the introduction of the Currency object, the currency
2418: // symbols in the DFS object are ignored. For backward
2419: // compatibility, we check any explicitly set DFS object. If it
2420: // is a default symbols object for its locale, we change the
2421: // currency object to one for that locale. If it is custom,
2422: // we set the currency to null.
2423: DecimalFormatSymbols def = new DecimalFormatSymbols(symbols
2424: .getLocale());
2425:
2426: if (symbols.getCurrencySymbol().equals(def.getCurrencySymbol())
2427: && symbols.getInternationalCurrencySymbol().equals(
2428: def.getInternationalCurrencySymbol())) {
2429: setCurrency(Currency.getInstance(symbols.getLocale()));
2430: } else {
2431: setCurrency(null);
2432: }
2433: }
2434:
2435: /**
2436: * Get the positive prefix.
2437: * <P>Examples: +123, $123, sFr123
2438: * @stable ICU 2.0
2439: */
2440: public String getPositivePrefix() {
2441: return positivePrefix;
2442: }
2443:
2444: /**
2445: * Set the positive prefix.
2446: * <P>Examples: +123, $123, sFr123
2447: * @stable ICU 2.0
2448: */
2449: public void setPositivePrefix(String newValue) {
2450: positivePrefix = newValue;
2451: posPrefixPattern = null;
2452: }
2453:
2454: /**
2455: * Get the negative prefix.
2456: * <P>Examples: -123, ($123) (with negative suffix), sFr-123
2457: * @stable ICU 2.0
2458: */
2459: public String getNegativePrefix() {
2460: return negativePrefix;
2461: }
2462:
2463: /**
2464: * Set the negative prefix.
2465: * <P>Examples: -123, ($123) (with negative suffix), sFr-123
2466: * @stable ICU 2.0
2467: */
2468: public void setNegativePrefix(String newValue) {
2469: negativePrefix = newValue;
2470: negPrefixPattern = null;
2471: }
2472:
2473: /**
2474: * Get the positive suffix.
2475: * <P>Example: 123%
2476: * @stable ICU 2.0
2477: */
2478: public String getPositiveSuffix() {
2479: return positiveSuffix;
2480: }
2481:
2482: /**
2483: * Set the positive suffix.
2484: * <P>Example: 123%
2485: * @stable ICU 2.0
2486: */
2487: public void setPositiveSuffix(String newValue) {
2488: positiveSuffix = newValue;
2489: posSuffixPattern = null;
2490: }
2491:
2492: /**
2493: * Get the negative suffix.
2494: * <P>Examples: -123%, ($123) (with positive suffixes)
2495: * @stable ICU 2.0
2496: */
2497: public String getNegativeSuffix() {
2498: return negativeSuffix;
2499: }
2500:
2501: /**
2502: * Set the positive suffix.
2503: * <P>Examples: 123%
2504: * @stable ICU 2.0
2505: */
2506: public void setNegativeSuffix(String newValue) {
2507: negativeSuffix = newValue;
2508: negSuffixPattern = null;
2509: }
2510:
2511: /**
2512: * Get the multiplier for use in percent, permill, etc.
2513: * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
2514: * (For Arabic, use arabic percent symbol).
2515: * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
2516: * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
2517: * @stable ICU 2.0
2518: */
2519: public int getMultiplier() {
2520: return multiplier;
2521: }
2522:
2523: /**
2524: * Set the multiplier for use in percent, permill, etc.
2525: * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
2526: * (For Arabic, use arabic percent symbol).
2527: * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
2528: * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
2529: * @stable ICU 2.0
2530: */
2531: public void setMultiplier(int newValue) {
2532: if (newValue <= 0) {
2533: throw new IllegalArgumentException("Bad multiplier: "
2534: + newValue);
2535: }
2536: multiplier = newValue;
2537: }
2538:
2539: /**
2540: * <strong><font face=helvetica color=red>NEW</font></strong>
2541: * Get the rounding increment.
2542: * @return A positive rounding increment, or <code>null</code> if rounding
2543: * is not in effect.
2544: * @see #setRoundingIncrement
2545: * @see #getRoundingMode
2546: * @see #setRoundingMode
2547: * @stable ICU 2.0
2548: */
2549: //#ifndef FOUNDATION
2550: public java.math.BigDecimal getRoundingIncrement() {
2551: if (roundingIncrementICU == null)
2552: return null;
2553: return roundingIncrementICU.toBigDecimal();
2554: }
2555:
2556: //#else
2557: //## public BigDecimal getRoundingIncrement() {
2558: //## if (roundingIncrementICU == null) return null;
2559: //## return new BigDecimal(roundingIncrementICU.toString());
2560: //## }
2561: //#endif
2562:
2563: //#ifndef FOUNDATION
2564: /**
2565: * <strong><font face=helvetica color=red>NEW</font></strong>
2566: * Set the rounding increment. This method also controls whether
2567: * rounding is enabled.
2568: * @param newValue A positive rounding increment, or <code>null</code> or
2569: * <code>BigDecimal(0.0)</code> to disable rounding.
2570: * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
2571: * @see #getRoundingIncrement
2572: * @see #getRoundingMode
2573: * @see #setRoundingMode
2574: * @stable ICU 2.0
2575: */
2576: public void setRoundingIncrement(java.math.BigDecimal newValue) {
2577: if (newValue == null) {
2578: setRoundingIncrement((BigDecimal) null);
2579: } else {
2580: setRoundingIncrement(new BigDecimal(newValue));
2581: }
2582: }
2583:
2584: //#endif
2585:
2586: /**
2587: * <strong><font face=helvetica color=red>NEW</font></strong>
2588: * Set the rounding increment. This method also controls whether
2589: * rounding is enabled.
2590: * @param newValue A positive rounding increment, or <code>null</code> or
2591: * <code>BigDecimal(0.0)</code> to disable rounding.
2592: * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
2593: * @see #getRoundingIncrement
2594: * @see #getRoundingMode
2595: * @see #setRoundingMode
2596: * @draft ICU 3.4.2
2597: * @provisional This API might change or be removed in a future release.
2598: */
2599: public void setRoundingIncrement(BigDecimal newValue) {
2600: int i = newValue == null ? 0 : newValue
2601: .compareTo(BigDecimal.ZERO);
2602: if (i < 0) {
2603: throw new IllegalArgumentException(
2604: "Illegal rounding increment");
2605: }
2606: if (i == 0) {
2607: setInternalRoundingIncrement(null);
2608: } else {
2609: setInternalRoundingIncrement(newValue);
2610: }
2611: setRoundingDouble();
2612: }
2613:
2614: /**
2615: * <strong><font face=helvetica color=red>NEW</font></strong>
2616: * Set the rounding increment. This method also controls whether
2617: * rounding is enabled.
2618: * @param newValue A positive rounding increment, or 0.0 to disable
2619: * rounding.
2620: * @exception IllegalArgumentException if <code>newValue</code> is < 0.0
2621: * @see #getRoundingIncrement
2622: * @see #getRoundingMode
2623: * @see #setRoundingMode
2624: * @stable ICU 2.0
2625: */
2626: public void setRoundingIncrement(double newValue) {
2627: if (newValue < 0.0) {
2628: throw new IllegalArgumentException(
2629: "Illegal rounding increment");
2630: }
2631: roundingDouble = newValue;
2632: roundingDoubleReciprocal = 0.0d;
2633: if (newValue == 0.0d) {
2634: setRoundingIncrement((BigDecimal) null);
2635: } else {
2636: roundingDouble = newValue;
2637: if (roundingDouble < 1.0d) {
2638: double rawRoundedReciprocal = 1.0d / roundingDouble;
2639: setRoundingDoubleReciprocal(rawRoundedReciprocal);
2640: }
2641: setInternalRoundingIncrement(new BigDecimal(newValue));
2642: }
2643: }
2644:
2645: private void setRoundingDoubleReciprocal(double rawRoundedReciprocal) {
2646: roundingDoubleReciprocal = Math.rint(rawRoundedReciprocal);
2647: if (Math.abs(rawRoundedReciprocal - roundingDoubleReciprocal) > roundingIncrementEpsilon) {
2648: roundingDoubleReciprocal = 0.0d;
2649: }
2650: }
2651:
2652: static final double roundingIncrementEpsilon = 0.000000001;
2653:
2654: /**
2655: * <strong><font face=helvetica color=red>NEW</font></strong>
2656: * Get the rounding mode.
2657: * @return A rounding mode, between <code>BigDecimal.ROUND_UP</code>
2658: * and <code>BigDecimal.ROUND_UNNECESSARY</code>.
2659: * @see #setRoundingIncrement
2660: * @see #getRoundingIncrement
2661: * @see #setRoundingMode
2662: * @see java.math.BigDecimal
2663: * @stable ICU 2.0
2664: */
2665: public int getRoundingMode() {
2666: return roundingMode;
2667: }
2668:
2669: /**
2670: * <strong><font face=helvetica color=red>NEW</font></strong>
2671: * Set the rounding mode. This has no effect unless the rounding
2672: * increment is greater than zero.
2673: * @param roundingMode A rounding mode, between
2674: * <code>BigDecimal.ROUND_UP</code> and
2675: * <code>BigDecimal.ROUND_UNNECESSARY</code>.
2676: * @exception IllegalArgumentException if <code>roundingMode</code>
2677: * is unrecognized.
2678: * @see #setRoundingIncrement
2679: * @see #getRoundingIncrement
2680: * @see #getRoundingMode
2681: * @see java.math.BigDecimal
2682: * @stable ICU 2.0
2683: */
2684: public void setRoundingMode(int roundingMode) {
2685: if (roundingMode < BigDecimal.ROUND_UP
2686: || roundingMode > BigDecimal.ROUND_UNNECESSARY) {
2687: throw new IllegalArgumentException(
2688: "Invalid rounding mode: " + roundingMode);
2689: }
2690: this .roundingMode = roundingMode;
2691: }
2692:
2693: /**
2694: * <strong><font face=helvetica color=red>NEW</font></strong>
2695: * Get the width to which the output of <code>format()</code> is padded.
2696: * The width is counted in 16-bit code units.
2697: * @return the format width, or zero if no padding is in effect
2698: * @see #setFormatWidth
2699: * @see #getPadCharacter
2700: * @see #setPadCharacter
2701: * @see #getPadPosition
2702: * @see #setPadPosition
2703: * @stable ICU 2.0
2704: */
2705: public int getFormatWidth() {
2706: return formatWidth;
2707: }
2708:
2709: /**
2710: * <strong><font face=helvetica color=red>NEW</font></strong>
2711: * Set the width to which the output of <code>format()</code> is padded.
2712: * The width is counted in 16-bit code units.
2713: * This method also controls whether padding is enabled.
2714: * @param width the width to which to pad the result of
2715: * <code>format()</code>, or zero to disable padding
2716: * @exception IllegalArgumentException if <code>width</code> is < 0
2717: * @see #getFormatWidth
2718: * @see #getPadCharacter
2719: * @see #setPadCharacter
2720: * @see #getPadPosition
2721: * @see #setPadPosition
2722: * @stable ICU 2.0
2723: */
2724: public void setFormatWidth(int width) {
2725: if (width < 0) {
2726: throw new IllegalArgumentException("Illegal format width");
2727: }
2728: formatWidth = width;
2729: }
2730:
2731: /**
2732: * <strong><font face=helvetica color=red>NEW</font></strong>
2733: * Get the character used to pad to the format width. The default is ' '.
2734: * @return the pad character
2735: * @see #setFormatWidth
2736: * @see #getFormatWidth
2737: * @see #setPadCharacter
2738: * @see #getPadPosition
2739: * @see #setPadPosition
2740: * @stable ICU 2.0
2741: */
2742: public char getPadCharacter() {
2743: return pad;
2744: }
2745:
2746: /**
2747: * <strong><font face=helvetica color=red>NEW</font></strong>
2748: * Set the character used to pad to the format width. If padding
2749: * is not enabled, then this will take effect if padding is later
2750: * enabled.
2751: * @param padChar the pad character
2752: * @see #setFormatWidth
2753: * @see #getFormatWidth
2754: * @see #getPadCharacter
2755: * @see #getPadPosition
2756: * @see #setPadPosition
2757: * @stable ICU 2.0
2758: */
2759: public void setPadCharacter(char padChar) {
2760: pad = padChar;
2761: }
2762:
2763: /**
2764: * <strong><font face=helvetica color=red>NEW</font></strong>
2765: * Get the position at which padding will take place. This is the location
2766: * at which padding will be inserted if the result of <code>format()</code>
2767: * is shorter than the format width.
2768: * @return the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
2769: * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
2770: * <code>PAD_AFTER_SUFFIX</code>.
2771: * @see #setFormatWidth
2772: * @see #getFormatWidth
2773: * @see #setPadCharacter
2774: * @see #getPadCharacter
2775: * @see #setPadPosition
2776: * @see #PAD_BEFORE_PREFIX
2777: * @see #PAD_AFTER_PREFIX
2778: * @see #PAD_BEFORE_SUFFIX
2779: * @see #PAD_AFTER_SUFFIX
2780: * @stable ICU 2.0
2781: */
2782: public int getPadPosition() {
2783: return padPosition;
2784: }
2785:
2786: /**
2787: * <strong><font face=helvetica color=red>NEW</font></strong>
2788: * Set the position at which padding will take place. This is the location
2789: * at which padding will be inserted if the result of <code>format()</code>
2790: * is shorter than the format width. This has no effect unless padding is
2791: * enabled.
2792: * @param padPos the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
2793: * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
2794: * <code>PAD_AFTER_SUFFIX</code>.
2795: * @exception IllegalArgumentException if the pad position in
2796: * unrecognized
2797: * @see #setFormatWidth
2798: * @see #getFormatWidth
2799: * @see #setPadCharacter
2800: * @see #getPadCharacter
2801: * @see #getPadPosition
2802: * @see #PAD_BEFORE_PREFIX
2803: * @see #PAD_AFTER_PREFIX
2804: * @see #PAD_BEFORE_SUFFIX
2805: * @see #PAD_AFTER_SUFFIX
2806: * @stable ICU 2.0
2807: */
2808: public void setPadPosition(int padPos) {
2809: if (padPos < PAD_BEFORE_PREFIX || padPos > PAD_AFTER_SUFFIX) {
2810: throw new IllegalArgumentException("Illegal pad position");
2811: }
2812: padPosition = padPos;
2813: }
2814:
2815: /**
2816: * <strong><font face=helvetica color=red>NEW</font></strong>
2817: * Return whether or not scientific notation is used.
2818: * @return true if this object formats and parses scientific notation
2819: * @see #setScientificNotation
2820: * @see #getMinimumExponentDigits
2821: * @see #setMinimumExponentDigits
2822: * @see #isExponentSignAlwaysShown
2823: * @see #setExponentSignAlwaysShown
2824: * @stable ICU 2.0
2825: */
2826: public boolean isScientificNotation() {
2827: return useExponentialNotation;
2828: }
2829:
2830: /**
2831: * <strong><font face=helvetica color=red>NEW</font></strong>
2832: * Set whether or not scientific notation is used. When scientific notation
2833: * is used, the effective maximum number of integer digits is <= 8. If the
2834: * maximum number of integer digits is set to more than 8, the effective
2835: * maximum will be 1. This allows this call to generate a 'default' scientific
2836: * number format without additional changes.
2837: * @param useScientific true if this object formats and parses scientific
2838: * notation
2839: * @see #isScientificNotation
2840: * @see #getMinimumExponentDigits
2841: * @see #setMinimumExponentDigits
2842: * @see #isExponentSignAlwaysShown
2843: * @see #setExponentSignAlwaysShown
2844: * @stable ICU 2.0
2845: */
2846: public void setScientificNotation(boolean useScientific) {
2847: useExponentialNotation = useScientific;
2848: }
2849:
2850: /**
2851: * <strong><font face=helvetica color=red>NEW</font></strong>
2852: * Return the minimum exponent digits that will be shown.
2853: * @return the minimum exponent digits that will be shown
2854: * @see #setScientificNotation
2855: * @see #isScientificNotation
2856: * @see #setMinimumExponentDigits
2857: * @see #isExponentSignAlwaysShown
2858: * @see #setExponentSignAlwaysShown
2859: * @stable ICU 2.0
2860: */
2861: public byte getMinimumExponentDigits() {
2862: return minExponentDigits;
2863: }
2864:
2865: /**
2866: * <strong><font face=helvetica color=red>NEW</font></strong>
2867: * Set the minimum exponent digits that will be shown. This has no
2868: * effect unless scientific notation is in use.
2869: * @param minExpDig a value >= 1 indicating the fewest exponent digits
2870: * that will be shown
2871: * @exception IllegalArgumentException if <code>minExpDig</code> < 1
2872: * @see #setScientificNotation
2873: * @see #isScientificNotation
2874: * @see #getMinimumExponentDigits
2875: * @see #isExponentSignAlwaysShown
2876: * @see #setExponentSignAlwaysShown
2877: * @stable ICU 2.0
2878: */
2879: public void setMinimumExponentDigits(byte minExpDig) {
2880: if (minExpDig < 1) {
2881: throw new IllegalArgumentException(
2882: "Exponent digits must be >= 1");
2883: }
2884: minExponentDigits = minExpDig;
2885: }
2886:
2887: /**
2888: * <strong><font face=helvetica color=red>NEW</font></strong>
2889: * Return whether the exponent sign is always shown.
2890: * @return true if the exponent is always prefixed with either the
2891: * localized minus sign or the localized plus sign, false if only negative
2892: * exponents are prefixed with the localized minus sign.
2893: * @see #setScientificNotation
2894: * @see #isScientificNotation
2895: * @see #setMinimumExponentDigits
2896: * @see #getMinimumExponentDigits
2897: * @see #setExponentSignAlwaysShown
2898: * @stable ICU 2.0
2899: */
2900: public boolean isExponentSignAlwaysShown() {
2901: return exponentSignAlwaysShown;
2902: }
2903:
2904: /**
2905: * <strong><font face=helvetica color=red>NEW</font></strong>
2906: * Set whether the exponent sign is always shown. This has no effect
2907: * unless scientific notation is in use.
2908: * @param expSignAlways true if the exponent is always prefixed with either
2909: * the localized minus sign or the localized plus sign, false if only
2910: * negative exponents are prefixed with the localized minus sign.
2911: * @see #setScientificNotation
2912: * @see #isScientificNotation
2913: * @see #setMinimumExponentDigits
2914: * @see #getMinimumExponentDigits
2915: * @see #isExponentSignAlwaysShown
2916: * @stable ICU 2.0
2917: */
2918: public void setExponentSignAlwaysShown(boolean expSignAlways) {
2919: exponentSignAlwaysShown = expSignAlways;
2920: }
2921:
2922: /**
2923: * Return the grouping size. Grouping size is the number of digits between
2924: * grouping separators in the integer portion of a number. For example,
2925: * in the number "123,456.78", the grouping size is 3.
2926: * @see #setGroupingSize
2927: * @see NumberFormat#isGroupingUsed
2928: * @see DecimalFormatSymbols#getGroupingSeparator
2929: * @stable ICU 2.0
2930: */
2931: public int getGroupingSize() {
2932: return groupingSize;
2933: }
2934:
2935: /**
2936: * Set the grouping size. Grouping size is the number of digits between
2937: * grouping separators in the integer portion of a number. For example,
2938: * in the number "123,456.78", the grouping size is 3.
2939: * @see #getGroupingSize
2940: * @see NumberFormat#setGroupingUsed
2941: * @see DecimalFormatSymbols#setGroupingSeparator
2942: * @stable ICU 2.0
2943: */
2944: public void setGroupingSize(int newValue) {
2945: groupingSize = (byte) newValue;
2946: }
2947:
2948: /**
2949: * Return the secondary grouping size. In some locales one
2950: * grouping interval is used for the least significant integer
2951: * digits (the primary grouping size), and another is used for all
2952: * others (the secondary grouping size). A formatter supporting a
2953: * secondary grouping size will return a positive integer unequal
2954: * to the primary grouping size returned by
2955: * <code>getGroupingSize()</code>. For example, if the primary
2956: * grouping size is 4, and the secondary grouping size is 2, then
2957: * the number 123456789 formats as "1,23,45,6789", and the pattern
2958: * appears as "#,##,###0".
2959: * [NEW]
2960: * @return the secondary grouping size, or a value less than
2961: * one if there is none
2962: * @see #setSecondaryGroupingSize
2963: * @see NumberFormat#isGroupingUsed
2964: * @see DecimalFormatSymbols#getGroupingSeparator
2965: * @stable ICU 2.0
2966: */
2967: public int getSecondaryGroupingSize() {
2968: return groupingSize2;
2969: }
2970:
2971: /**
2972: * Set the secondary grouping size. If set to a value less than 1,
2973: * then secondary grouping is turned off, and the primary grouping
2974: * size is used for all intervals, not just the least significant.
2975: * [NEW]
2976: * @see #getSecondaryGroupingSize
2977: * @see NumberFormat#setGroupingUsed
2978: * @see DecimalFormatSymbols#setGroupingSeparator
2979: * @stable ICU 2.0
2980: */
2981: public void setSecondaryGroupingSize(int newValue) {
2982: groupingSize2 = (byte) newValue;
2983: }
2984:
2985: /**
2986: * Allows you to get the behavior of the decimal separator with integers.
2987: * (The decimal separator will always appear with decimals.)
2988: * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
2989: * @stable ICU 2.0
2990: */
2991: public boolean isDecimalSeparatorAlwaysShown() {
2992: return decimalSeparatorAlwaysShown;
2993: }
2994:
2995: /**
2996: * Allows you to set the behavior of the decimal separator with integers.
2997: * (The decimal separator will always appear with decimals.)
2998: *
2999: * <p>This only affects formatting, and only where
3000: * there might be no digits after the decimal point, e.g.,
3001: * if true, 3456.00 -> "3,456."
3002: * if false, 3456.00 -> "3456"
3003: * This is independent of parsing. If you want parsing to stop at the decimal
3004: * point, use setParseIntegerOnly.
3005: *
3006: * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
3007: * @stable ICU 2.0
3008: */
3009: public void setDecimalSeparatorAlwaysShown(boolean newValue) {
3010: decimalSeparatorAlwaysShown = newValue;
3011: }
3012:
3013: /**
3014: * Standard override; no change in semantics.
3015: * @stable ICU 2.0
3016: */
3017: public Object clone() {
3018: try {
3019: DecimalFormat other = (DecimalFormat) super .clone();
3020: other.symbols = (DecimalFormatSymbols) symbols.clone();
3021: other.digitList = new DigitList(); // fix for JB#5358
3022: /*
3023: * TODO: We need to figure out whether we share a single copy
3024: * of DigitList by multiple cloned copies. format/subformat
3025: * are designed to use a single instance, but parse/subparse
3026: * implementation is not.
3027: */
3028: return other;
3029: } catch (Exception e) {
3030: throw new IllegalStateException();
3031: }
3032: }
3033:
3034: /**
3035: * Overrides equals
3036: * @stable ICU 2.0
3037: */
3038: public boolean equals(Object obj) {
3039: if (obj == null)
3040: return false;
3041: if (!super .equals(obj))
3042: return false; // super does class check
3043:
3044: DecimalFormat other = (DecimalFormat) obj;
3045: /* Add the comparison of the four new added fields ,they are
3046: * posPrefixPattern, posSuffixPattern, negPrefixPattern, negSuffixPattern.
3047: * [Richard/GCL]
3048: */
3049: return (posPrefixPattern != null && equals(posPrefixPattern,
3050: other.posPrefixPattern))
3051: && (posSuffixPattern != null && equals(
3052: posSuffixPattern, other.posSuffixPattern))
3053: && (negPrefixPattern != null && equals(
3054: negPrefixPattern, other.negPrefixPattern))
3055: && (negSuffixPattern != null && equals(
3056: negSuffixPattern, other.negSuffixPattern))
3057: && multiplier == other.multiplier
3058: && groupingSize == other.groupingSize
3059: && groupingSize2 == other.groupingSize2
3060: && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
3061: && useExponentialNotation == other.useExponentialNotation
3062: && (!useExponentialNotation || minExponentDigits == other.minExponentDigits)
3063: && useSignificantDigits == other.useSignificantDigits
3064: && (!useSignificantDigits || minSignificantDigits == other.minSignificantDigits
3065: && maxSignificantDigits == other.maxSignificantDigits)
3066: && symbols.equals(other.symbols);
3067: }
3068:
3069: //method to unquote the strings and compare
3070: private boolean equals(String pat1, String pat2) {
3071: //fast path
3072: if (pat1.equals(pat2)) {
3073: return true;
3074: }
3075: return unquote(pat1).equals(unquote(pat2));
3076: }
3077:
3078: private String unquote(String pat) {
3079: StringBuffer buf = new StringBuffer(pat.length());
3080: int i = 0;
3081: while (i < pat.length()) {
3082: char ch = pat.charAt(i++);
3083: if (ch != QUOTE) {
3084: buf.append(ch);
3085: }
3086: }
3087: return buf.toString();
3088: }
3089:
3090: // protected void handleToString(StringBuffer buf) {
3091: // buf.append("\nposPrefixPattern: '" + posPrefixPattern + "'\n");
3092: // buf.append("positivePrefix: '" + positivePrefix + "'\n");
3093: // buf.append("posSuffixPattern: '" + posSuffixPattern + "'\n");
3094: // buf.append("positiveSuffix: '" + positiveSuffix + "'\n");
3095: // buf.append("negPrefixPattern: '" + com.ibm.icu.impl.Utility.format1ForSource(negPrefixPattern) + "'\n");
3096: // buf.append("negativePrefix: '" + com.ibm.icu.impl.Utility.format1ForSource(negativePrefix) + "'\n");
3097: // buf.append("negSuffixPattern: '" + negSuffixPattern + "'\n");
3098: // buf.append("negativeSuffix: '" + negativeSuffix + "'\n");
3099: // buf.append("multiplier: '" + multiplier + "'\n");
3100: // buf.append("groupingSize: '" + groupingSize + "'\n");
3101: // buf.append("groupingSize2: '" + groupingSize2 + "'\n");
3102: // buf.append("decimalSeparatorAlwaysShown: '" + decimalSeparatorAlwaysShown + "'\n");
3103: // buf.append("useExponentialNotation: '" + useExponentialNotation + "'\n");
3104: // buf.append("minExponentDigits: '" + minExponentDigits + "'\n");
3105: // buf.append("useSignificantDigits: '" + useSignificantDigits + "'\n");
3106: // buf.append("minSignificantDigits: '" + minSignificantDigits + "'\n");
3107: // buf.append("maxSignificantDigits: '" + maxSignificantDigits + "'\n");
3108: // buf.append("symbols: '" + symbols + "'");
3109: // }
3110:
3111: /**
3112: * Overrides hashCode
3113: * @stable ICU 2.0
3114: */
3115: public int hashCode() {
3116: return super .hashCode() * 37 + positivePrefix.hashCode();
3117: // just enough fields for a reasonable distribution
3118: }
3119:
3120: /**
3121: * Synthesizes a pattern string that represents the current state
3122: * of this Format object.
3123: * @see #applyPattern
3124: * @stable ICU 2.0
3125: */
3126: public String toPattern() {
3127: return toPattern(false);
3128: }
3129:
3130: /**
3131: * Synthesizes a localized pattern string that represents the current
3132: * state of this Format object.
3133: * @see #applyPattern
3134: * @stable ICU 2.0
3135: */
3136: public String toLocalizedPattern() {
3137: return toPattern(true);
3138: }
3139:
3140: /**
3141: * Expand the affix pattern strings into the expanded affix strings. If any
3142: * affix pattern string is null, do not expand it. This method should be
3143: * called any time the symbols or the affix patterns change in order to keep
3144: * the expanded affix strings up to date.
3145: */
3146: //Bug 4212072 [Richard/GCL]
3147: private void expandAffixes() {
3148: // expandAffix() will set currencyChoice to a non-null value if
3149: // appropriate AND if it is null.
3150: currencyChoice = null;
3151:
3152: // Reuse one StringBuffer for better performance
3153: StringBuffer buffer = new StringBuffer();
3154: if (posPrefixPattern != null) {
3155: expandAffix(posPrefixPattern, buffer, false);
3156: positivePrefix = buffer.toString();
3157: }
3158: if (posSuffixPattern != null) {
3159: expandAffix(posSuffixPattern, buffer, false);
3160: positiveSuffix = buffer.toString();
3161: }
3162: if (negPrefixPattern != null) {
3163: expandAffix(negPrefixPattern, buffer, false);
3164: negativePrefix = buffer.toString();
3165: }
3166: if (negSuffixPattern != null) {
3167: expandAffix(negSuffixPattern, buffer, false);
3168: negativeSuffix = buffer.toString();
3169: }
3170: }
3171:
3172: /**
3173: * Expand an affix pattern into an affix string. All characters in
3174: * the pattern are literal unless bracketed by QUOTEs. The
3175: * following characters outside QUOTE are recognized:
3176: * PATTERN_PERCENT, PATTERN_PER_MILLE, PATTERN_MINUS, and
3177: * CURRENCY_SIGN. If CURRENCY_SIGN is doubled, it is interpreted as
3178: * an international currency sign. Any other character outside
3179: * QUOTE represents itself. Quoted text must be well-formed.
3180: *
3181: * This method is used in two distinct ways. First, it is used to expand
3182: * the stored affix patterns into actual affixes. For this usage, doFormat
3183: * must be false. Second, it is used to expand the stored affix patterns
3184: * given a specific number (doFormat == true), for those rare cases in
3185: * which a currency format references a ChoiceFormat (e.g., en_IN display
3186: * name for INR). The number itself is taken from digitList.
3187: *
3188: * When used in the first way, this method has a side effect: It sets
3189: * currencyChoice to a ChoiceFormat object, if the currency's display name
3190: * in this locale is a ChoiceFormat pattern (very rare). It only does this
3191: * if currencyChoice is null to start with.
3192: *
3193: * @param pattern the non-null, possibly empty pattern
3194: * @param buffer a scratch StringBuffer; its contents will be lost
3195: * @param doFormat if false, then the pattern will be expanded, and if a
3196: * currency symbol is encountered that expands to a ChoiceFormat, the
3197: * currencyChoice member variable will be initialized if it is null. If
3198: * doFormat is true, then it is assumed that the currencyChoice has been
3199: * created, and it will be used to format the value in digitList.
3200: * @return the expanded equivalent of pattern
3201: */
3202: //Bug 4212072 [Richard/GCL]
3203: private void expandAffix(String pattern, StringBuffer buffer,
3204: boolean doFormat) {
3205: buffer.setLength(0);
3206: for (int i = 0; i < pattern.length();) {
3207: char c = pattern.charAt(i++);
3208: if (c == QUOTE) {
3209: for (;;) {
3210: int j = pattern.indexOf(QUOTE, i);
3211: if (j == i) {
3212: buffer.append(QUOTE);
3213: i = j + 1;
3214: break;
3215: } else if (j > i) {
3216: buffer.append(pattern.substring(i, j));
3217: i = j + 1;
3218: if (i < pattern.length()
3219: && pattern.charAt(i) == QUOTE) {
3220: buffer.append(QUOTE);
3221: ++i;
3222: // loop again
3223: } else {
3224: break;
3225: }
3226: } else {
3227: // Unterminated quote; should be caught by apply
3228: // pattern.
3229: throw new RuntimeException();
3230: }
3231: }
3232: continue;
3233: }
3234:
3235: switch (c) {
3236: case CURRENCY_SIGN:
3237: // As of ICU 2.2 we use the currency object, and
3238: // ignore the currency symbols in the DFS, unless
3239: // we have a null currency object. This occurs if
3240: // resurrecting a pre-2.2 object or if the user
3241: // sets a custom DFS.
3242: boolean intl = i < pattern.length()
3243: && pattern.charAt(i) == CURRENCY_SIGN;
3244: if (intl) {
3245: ++i;
3246: }
3247: String s = null;
3248: Currency currency = getCurrency();
3249: if (currency != null) {
3250: if (!intl) {
3251: boolean isChoiceFormat[] = new boolean[1];
3252: s = currency.getName(symbols.getULocale(),
3253: Currency.SYMBOL_NAME, isChoiceFormat);
3254: if (isChoiceFormat[0]) {
3255: // Two modes here: If doFormat is false, we set up
3256: // currencyChoice. If doFormat is true, we use the
3257: // previously created currencyChoice to format the
3258: // value in digitList.
3259: if (!doFormat) {
3260: // If the currency is handled by a ChoiceFormat,
3261: // then we're not going to use the expanded
3262: // patterns. Instantiate the ChoiceFormat and
3263: // return.
3264: if (currencyChoice == null) {
3265: currencyChoice = new ChoiceFormat(s);
3266: }
3267: // We could almost return null or "" here, since the
3268: // expanded affixes are almost not used at all
3269: // in this situation. However, one method --
3270: // toPattern() -- still does use the expanded
3271: // affixes, in order to set up a padding
3272: // pattern. We use the CURRENCY_SIGN as a
3273: // placeholder.
3274: s = String.valueOf(CURRENCY_SIGN);
3275: } else {
3276: FieldPosition pos = new FieldPosition(0); // ignored
3277: currencyChoice.format(digitList
3278: .getDouble(), buffer, pos);
3279: continue;
3280: }
3281: }
3282: } else {
3283: s = currency.getCurrencyCode();
3284: }
3285: } else {
3286: s = intl ? symbols.getInternationalCurrencySymbol()
3287: : symbols.getCurrencySymbol();
3288: }
3289: buffer.append(s);
3290: continue;
3291: case PATTERN_PERCENT:
3292: c = symbols.getPercent();
3293: break;
3294: case PATTERN_PER_MILLE:
3295: c = symbols.getPerMill();
3296: break;
3297: case PATTERN_MINUS:
3298: c = symbols.getMinusSign();
3299: break;
3300: }
3301: buffer.append(c);
3302: }
3303: }
3304:
3305: /**
3306: * Append an affix to the given StringBuffer.
3307: * @param buf buffer to append to
3308: * @param isNegative
3309: * @param isPrefix
3310: */
3311: private int appendAffix(StringBuffer buf, boolean isNegative,
3312: boolean isPrefix, boolean parseAttr) {
3313: if (currencyChoice != null) {
3314: String affixPat = null;
3315: if (isPrefix) {
3316: affixPat = isNegative ? negPrefixPattern
3317: : posPrefixPattern;
3318: } else {
3319: affixPat = isNegative ? negSuffixPattern
3320: : posSuffixPattern;
3321: }
3322: StringBuffer affixBuf = new StringBuffer();
3323: expandAffix(affixPat, affixBuf, true);
3324: buf.append(affixBuf.toString());
3325: return affixBuf.length();
3326: }
3327:
3328: String affix = null;
3329: if (isPrefix) {
3330: affix = isNegative ? negativePrefix : positivePrefix;
3331: } else {
3332: affix = isNegative ? negativeSuffix : positiveSuffix;
3333: }
3334: //#ifndef FOUNDATION
3335: // [Spark/CDL] Invoke formatAffix2Attribute to add attributes for affix
3336: if (parseAttr) {
3337: int offset = affix.indexOf(symbols.getCurrencySymbol());
3338: if (-1 == offset) {
3339: offset = affix.indexOf(symbols.getPercent());
3340: if (-1 == offset) {
3341: offset = 0;
3342: }
3343: }
3344: formatAffix2Attribute(affix, buf.length() + offset, buf
3345: .length()
3346: + affix.length());
3347: }
3348: //#endif
3349: buf.append(affix);
3350: return affix.length();
3351: }
3352:
3353: //#ifndef FOUNDATION
3354: /*
3355: * [Spark/CDL] This is a newly added method, used to add attributes for
3356: * prefix and suffix.
3357: */
3358: private void formatAffix2Attribute(String affix, int begin, int end) {
3359: // [Spark/CDL] It is the invoker's responsibility to ensure that, before
3360: // the invocation of
3361: // this method, attributes is not null.
3362: // if( attributes == null ) return;
3363: if (affix.indexOf(symbols.getCurrencySymbol()) > -1) {
3364: addAttribute(Field.CURRENCY, begin, end);
3365: } else if (affix.indexOf(symbols.getMinusSign()) > -1) {
3366: addAttribute(Field.SIGN, begin, end);
3367: } else if (affix.indexOf(symbols.getPercent()) > -1) {
3368: addAttribute(Field.PERCENT, begin, end);
3369: } else if (affix.indexOf(symbols.getPerMill()) > -1) {
3370: addAttribute(Field.PERMILLE, begin, end);
3371: }
3372: }
3373:
3374: //#endif
3375:
3376: //#ifndef FOUNDATION
3377: /*
3378: * [Spark/CDL] Use this method to add attribute.
3379: */
3380: private void addAttribute(Field field, int begin, int end) {
3381: FieldPosition pos = new FieldPosition(field);
3382: pos.setBeginIndex(begin);
3383: pos.setEndIndex(end);
3384: attributes.add(pos);
3385: }
3386:
3387: //#endif
3388:
3389: //#ifndef FOUNDATION
3390: /**
3391: * Format the object to an attributed string, and return the corresponding iterator
3392: * Overrides superclass method.
3393: * @stable ICU 3.6
3394: */
3395: // [Spark/CDL]
3396: public AttributedCharacterIterator formatToCharacterIterator(
3397: Object obj) {
3398: if (!(obj instanceof Number))
3399: throw new IllegalArgumentException();
3400: Number number = (Number) obj;
3401: StringBuffer text = null;
3402: attributes.clear();
3403: if (obj instanceof BigInteger) {
3404: text = format((BigInteger) number, new StringBuffer(),
3405: new FieldPosition(0), true);
3406: } else if (obj instanceof java.math.BigDecimal) {
3407: text = format((java.math.BigDecimal) number,
3408: new StringBuffer(), new FieldPosition(0), true);
3409: } else if (obj instanceof Double) {
3410: text = format(number.doubleValue(), new StringBuffer(),
3411: new FieldPosition(0), true);
3412: } else if (obj instanceof Integer || obj instanceof Long) {
3413: text = format(number.longValue(), new StringBuffer(),
3414: new FieldPosition(0), true);
3415: }
3416:
3417: AttributedString as = new AttributedString(text.toString());
3418:
3419: // add NumberFormat field attributes to the AttributedString
3420: for (int i = 0; i < attributes.size(); i++) {
3421: FieldPosition pos = (FieldPosition) attributes.get(i);
3422: Format.Field attribute = pos.getFieldAttribute();
3423: as.addAttribute(attribute, attribute, pos.getBeginIndex(),
3424: pos.getEndIndex());
3425: }
3426:
3427: // return the CharacterIterator from AttributedString
3428: return as.getIterator();
3429: }
3430:
3431: //#endif
3432: /**
3433: * Append an affix pattern to the given StringBuffer. Localize unquoted
3434: * specials.
3435: */
3436: private void appendAffixPattern(StringBuffer buffer,
3437: boolean isNegative, boolean isPrefix, boolean localized) {
3438: String affixPat = null;
3439: if (isPrefix) {
3440: affixPat = isNegative ? negPrefixPattern : posPrefixPattern;
3441: } else {
3442: affixPat = isNegative ? negSuffixPattern : posSuffixPattern;
3443: }
3444:
3445: // When there is a null affix pattern, we use the affix itself.
3446: if (affixPat == null) {
3447: String affix = null;
3448: if (isPrefix) {
3449: affix = isNegative ? negativePrefix : positivePrefix;
3450: } else {
3451: affix = isNegative ? negativeSuffix : positiveSuffix;
3452: }
3453: // Do this crudely for now: Wrap everything in quotes.
3454: buffer.append(QUOTE);
3455: for (int i = 0; i < affix.length(); ++i) {
3456: char ch = affix.charAt(i);
3457: if (ch == QUOTE) {
3458: buffer.append(ch);
3459: }
3460: buffer.append(ch);
3461: }
3462: buffer.append(QUOTE);
3463: return;
3464: }
3465:
3466: if (!localized) {
3467: buffer.append(affixPat);
3468: } else {
3469: int i, j;
3470: for (i = 0; i < affixPat.length(); ++i) {
3471: char ch = affixPat.charAt(i);
3472: switch (ch) {
3473: case QUOTE:
3474: j = affixPat.indexOf(QUOTE, i + 1);
3475: if (j < 0) {
3476: throw new IllegalArgumentException(
3477: "Malformed affix pattern: " + affixPat);
3478: }
3479: buffer.append(affixPat.substring(i, j + 1));
3480: i = j;
3481: continue;
3482: case PATTERN_PER_MILLE:
3483: ch = symbols.getPerMill();
3484: break;
3485: case PATTERN_PERCENT:
3486: ch = symbols.getPercent();
3487: break;
3488: case PATTERN_MINUS:
3489: ch = symbols.getMinusSign();
3490: break;
3491: }
3492: //check if char is same as any other symbol
3493: if (ch == symbols.getDecimalSeparator()
3494: || ch == symbols.getGroupingSeparator()) {
3495: buffer.append(QUOTE);
3496: buffer.append(ch);
3497: buffer.append(QUOTE);
3498: } else {
3499: buffer.append(ch);
3500: }
3501: }
3502: }
3503: }
3504:
3505: /**
3506: * <strong><font face=helvetica color=red>CHANGED</font></strong>
3507: * Does the real work of generating a pattern.
3508: */
3509: private String toPattern(boolean localized) {
3510: StringBuffer result = new StringBuffer();
3511: char zero = localized ? symbols.getZeroDigit()
3512: : PATTERN_ZERO_DIGIT;
3513: char digit = localized ? symbols.getDigit() : PATTERN_DIGIT;
3514: char sigDigit = 0;
3515: boolean useSigDig = areSignificantDigitsUsed();
3516: if (useSigDig) {
3517: sigDigit = localized ? symbols.getSignificantDigit()
3518: : PATTERN_SIGNIFICANT_DIGIT;
3519: }
3520: char group = localized ? symbols.getGroupingSeparator()
3521: : PATTERN_GROUPING_SEPARATOR;
3522: int i;
3523: int roundingDecimalPos = 0; // Pos of decimal in roundingDigits
3524: String roundingDigits = null;
3525: int padPos = (formatWidth > 0) ? padPosition : -1;
3526: String padSpec = (formatWidth > 0) ? new StringBuffer(2)
3527: .append(
3528: localized ? symbols.getPadEscape()
3529: : PATTERN_PAD_ESCAPE).append(pad)
3530: .toString() : null;
3531: if (roundingIncrementICU != null) {
3532: i = roundingIncrementICU.scale();
3533: roundingDigits = roundingIncrementICU.movePointRight(i)
3534: .toString();
3535: roundingDecimalPos = roundingDigits.length() - i;
3536: }
3537: for (int part = 0; part < 2; ++part) {
3538: // variable not used int partStart = result.length();
3539: if (padPos == PAD_BEFORE_PREFIX) {
3540: result.append(padSpec);
3541: }
3542: /* Use original symbols read from resources in pattern
3543: * eg. use "\u00A4" instead of "$" in Locale.US [Richard/GCL]
3544: */
3545: appendAffixPattern(result, part != 0, true, localized);
3546: if (padPos == PAD_AFTER_PREFIX) {
3547: result.append(padSpec);
3548: }
3549: int sub0Start = result.length();
3550: int g = isGroupingUsed() ? Math.max(0, groupingSize) : 0;
3551: if (g > 0 && groupingSize2 > 0
3552: && groupingSize2 != groupingSize) {
3553: g += groupingSize2;
3554: }
3555: int maxDig = 0, minDig = 0, maxSigDig = 0;
3556: if (useSigDig) {
3557: minDig = getMinimumSignificantDigits();
3558: maxDig = maxSigDig = getMaximumSignificantDigits();
3559: } else {
3560: minDig = getMinimumIntegerDigits();
3561: maxDig = getMaximumIntegerDigits();
3562: }
3563: if (useExponentialNotation) {
3564: if (maxDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
3565: maxDig = 1;
3566: }
3567: } else if (useSigDig) {
3568: maxDig = Math.max(maxDig, g + 1);
3569: } else {
3570: maxDig = Math.max(Math
3571: .max(g, getMinimumIntegerDigits()),
3572: roundingDecimalPos) + 1;
3573: }
3574: for (i = maxDig; i > 0; --i) {
3575: if (!useExponentialNotation && i < maxDig
3576: && isGroupingPosition(i)) {
3577: result.append(group);
3578: }
3579: if (useSigDig) {
3580: // #@,@### (maxSigDig == 5, minSigDig == 2)
3581: // 65 4321 (1-based pos, count from the right)
3582: // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig)
3583: // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig
3584: result
3585: .append((maxSigDig >= i && i > (maxSigDig - minDig)) ? sigDigit
3586: : digit);
3587: } else {
3588: if (roundingDigits != null) {
3589: int pos = roundingDecimalPos - i;
3590: if (pos >= 0 && pos < roundingDigits.length()) {
3591: result.append((char) (roundingDigits
3592: .charAt(pos) - '0' + zero));
3593: continue;
3594: }
3595: }
3596: result.append(i <= minDig ? zero : digit);
3597: }
3598: }
3599: if (!useSigDig) {
3600: if (getMaximumFractionDigits() > 0
3601: || decimalSeparatorAlwaysShown) {
3602: result.append(localized ? symbols
3603: .getDecimalSeparator()
3604: : PATTERN_DECIMAL_SEPARATOR);
3605: }
3606: int pos = roundingDecimalPos;
3607: for (i = 0; i < getMaximumFractionDigits(); ++i) {
3608: if (roundingDigits != null
3609: && pos < roundingDigits.length()) {
3610: result
3611: .append(pos < 0 ? zero
3612: : (char) (roundingDigits
3613: .charAt(pos) - '0' + zero));
3614: ++pos;
3615: continue;
3616: }
3617: result.append(i < getMinimumFractionDigits() ? zero
3618: : digit);
3619: }
3620: }
3621: if (useExponentialNotation) {
3622: if (localized) {
3623: result.append(symbols.getExponentSeparator());
3624: } else {
3625: result.append(PATTERN_EXPONENT);
3626: }
3627: if (exponentSignAlwaysShown) {
3628: result.append(localized ? symbols.getPlusSign()
3629: : PATTERN_PLUS_SIGN);
3630: }
3631: for (i = 0; i < minExponentDigits; ++i) {
3632: result.append(zero);
3633: }
3634: }
3635: if (padSpec != null && !useExponentialNotation) {
3636: int add = formatWidth
3637: - result.length()
3638: + sub0Start
3639: - ((part == 0) ? positivePrefix.length()
3640: + positiveSuffix.length()
3641: : negativePrefix.length()
3642: + negativeSuffix.length());
3643: while (add > 0) {
3644: result.insert(sub0Start, digit);
3645: ++maxDig;
3646: --add;
3647: // Only add a grouping separator if we have at least
3648: // 2 additional characters to be added, so we don't
3649: // end up with ",###".
3650: if (add > 1 && isGroupingPosition(maxDig)) {
3651: result.insert(sub0Start, group);
3652: --add;
3653: }
3654: }
3655: }
3656: if (padPos == PAD_BEFORE_SUFFIX) {
3657: result.append(padSpec);
3658: }
3659: /* Use original symbols read from resources in pattern
3660: * eg. use "\u00A4" instead of "$" in Locale.US [Richard/GCL]
3661: */
3662: appendAffixPattern(result, part != 0, false, localized);
3663: if (padPos == PAD_AFTER_SUFFIX) {
3664: result.append(padSpec);
3665: }
3666: if (part == 0) {
3667: if (negativeSuffix.equals(positiveSuffix)
3668: && negativePrefix.equals(PATTERN_MINUS
3669: + positivePrefix)) {
3670: break;
3671: } else {
3672: result.append(localized ? symbols
3673: .getPatternSeparator() : PATTERN_SEPARATOR);
3674: }
3675: }
3676: }
3677: return result.toString();
3678: }
3679:
3680: /**
3681: * Apply the given pattern to this Format object. A pattern is a
3682: * short-hand specification for the various formatting properties.
3683: * These properties can also be changed individually through the
3684: * various setter methods.
3685: * <p>
3686: * There is no limit to integer digits are set
3687: * by this routine, since that is the typical end-user desire;
3688: * use setMaximumInteger if you want to set a real value.
3689: * For negative numbers, use a second pattern, separated by a semicolon
3690: * <P>Example "#,#00.0#" -> 1,234.56
3691: * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
3692: * a maximum of 2 fraction digits.
3693: * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parentheses.
3694: * <p>In negative patterns, the minimum and maximum counts are ignored;
3695: * these are presumed to be set in the positive pattern.
3696: * @stable ICU 2.0
3697: */
3698: public void applyPattern(String pattern) {
3699: applyPattern(pattern, false);
3700: }
3701:
3702: /**
3703: * Apply the given pattern to this Format object. The pattern
3704: * is assumed to be in a localized notation. A pattern is a
3705: * short-hand specification for the various formatting properties.
3706: * These properties can also be changed individually through the
3707: * various setter methods.
3708: * <p>
3709: * There is no limit to integer digits are set
3710: * by this routine, since that is the typical end-user desire;
3711: * use setMaximumInteger if you want to set a real value.
3712: * For negative numbers, use a second pattern, separated by a semicolon
3713: * <P>Example "#,#00.0#" -> 1,234.56
3714: * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
3715: * a maximum of 2 fraction digits.
3716: * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
3717: * <p>In negative patterns, the minimum and maximum counts are ignored;
3718: * these are presumed to be set in the positive pattern.
3719: * @stable ICU 2.0
3720: */
3721: public void applyLocalizedPattern(String pattern) {
3722: applyPattern(pattern, true);
3723: }
3724:
3725: /**
3726: * <strong><font face=helvetica color=red>CHANGED</font></strong>
3727: * Does the real work of applying a pattern.
3728: */
3729: private void applyPattern(String pattern, boolean localized) {
3730: char zeroDigit = PATTERN_ZERO_DIGIT; // '0'
3731: char sigDigit = PATTERN_SIGNIFICANT_DIGIT; // '@'
3732: char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
3733: char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
3734: char percent = PATTERN_PERCENT;
3735: char perMill = PATTERN_PER_MILLE;
3736: char digit = PATTERN_DIGIT; // '#'
3737: char separator = PATTERN_SEPARATOR;
3738: String exponent = String.valueOf(PATTERN_EXPONENT);
3739: char plus = PATTERN_PLUS_SIGN;
3740: char padEscape = PATTERN_PAD_ESCAPE;
3741: char minus = PATTERN_MINUS; //Bug 4212072 [Richard/GCL]
3742: if (localized) {
3743: zeroDigit = symbols.getZeroDigit();
3744: sigDigit = symbols.getSignificantDigit();
3745: groupingSeparator = symbols.getGroupingSeparator();
3746: decimalSeparator = symbols.getDecimalSeparator();
3747: percent = symbols.getPercent();
3748: perMill = symbols.getPerMill();
3749: digit = symbols.getDigit();
3750: separator = symbols.getPatternSeparator();
3751: exponent = symbols.getExponentSeparator();
3752: plus = symbols.getPlusSign();
3753: padEscape = symbols.getPadEscape();
3754: minus = symbols.getMinusSign(); //Bug 4212072 [Richard/GCL]
3755: }
3756: char nineDigit = (char) (zeroDigit + 9);
3757:
3758: boolean gotNegative = false;
3759:
3760: int pos = 0;
3761: // Part 0 is the positive pattern. Part 1, if present, is the negative
3762: // pattern.
3763: for (int part = 0; part < 2 && pos < pattern.length(); ++part) {
3764: // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
3765: // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
3766: // between the prefix and suffix, and consists of pattern
3767: // characters. In the prefix and suffix, percent, permille, and
3768: // currency symbols are recognized and translated.
3769: int subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
3770:
3771: // It's important that we don't change any fields of this object
3772: // prematurely. We set the following variables for the multiplier,
3773: // grouping, etc., and then only change the actual object fields if
3774: // everything parses correctly. This also lets us register
3775: // the data from part 0 and ignore the part 1, except for the
3776: // prefix and suffix.
3777: StringBuffer prefix = new StringBuffer();
3778: StringBuffer suffix = new StringBuffer();
3779: int decimalPos = -1;
3780: int multiplier = 1;
3781: int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
3782: byte groupingCount = -1;
3783: byte groupingCount2 = -1;
3784: int padPos = -1;
3785: char padChar = 0;
3786: int incrementPos = -1;
3787: long incrementVal = 0;
3788: byte expDigits = -1;
3789: boolean expSignAlways = false;
3790: boolean isCurrency = false;
3791:
3792: // The affix is either the prefix or the suffix.
3793: StringBuffer affix = prefix;
3794:
3795: int start = pos;
3796:
3797: PARTLOOP: for (; pos < pattern.length(); ++pos) {
3798: char ch = pattern.charAt(pos);
3799: switch (subpart) {
3800: case 0: // Pattern proper subpart (between prefix & suffix)
3801: // Process the digits, decimal, and grouping characters. We
3802: // record five pieces of information. We expect the digits
3803: // to occur in the pattern ####00.00####, and we record the
3804: // number of left digits, zero (central) digits, and right
3805: // digits. The position of the last grouping character is
3806: // recorded (should be somewhere within the first two blocks
3807: // of characters), as is the position of the decimal point,
3808: // if any (should be in the zero digits). If there is no
3809: // decimal point, then there should be no right digits.
3810: if (ch == digit) {
3811: if (zeroDigitCount > 0 || sigDigitCount > 0) {
3812: ++digitRightCount;
3813: } else {
3814: ++digitLeftCount;
3815: }
3816: if (groupingCount >= 0 && decimalPos < 0) {
3817: ++groupingCount;
3818: }
3819: } else if ((ch >= zeroDigit && ch <= nineDigit)
3820: || ch == sigDigit) {
3821: if (digitRightCount > 0) {
3822: patternError("Unexpected '" + ch + '\'',
3823: pattern);
3824: }
3825: if (ch == sigDigit) {
3826: ++sigDigitCount;
3827: } else {
3828: ++zeroDigitCount;
3829: if (ch != zeroDigit) {
3830: int p = digitLeftCount + zeroDigitCount
3831: + digitRightCount;
3832: if (incrementPos >= 0) {
3833: while (incrementPos < p) {
3834: incrementVal *= 10;
3835: ++incrementPos;
3836: }
3837: } else {
3838: incrementPos = p;
3839: }
3840: incrementVal += ch - zeroDigit;
3841: }
3842: }
3843: if (groupingCount >= 0 && decimalPos < 0) {
3844: ++groupingCount;
3845: }
3846: } else if (ch == groupingSeparator) {
3847: /*Bug 4212072
3848: process the Localized pattern like "'Fr. '#'##0.05;'Fr.-'#'##0.05"
3849: (Locale="CH", groupingSeparator == QUOTE)
3850: [Richard/GCL]
3851: */
3852: if (ch == QUOTE && (pos + 1) < pattern.length()) {
3853: char after = pattern.charAt(pos + 1);
3854: if (!(after == digit || (after >= zeroDigit && after <= nineDigit))) {
3855: // A quote outside quotes indicates either the opening
3856: // quote or two quotes, which is a quote literal. That is,
3857: // we have the first quote in 'do' or o''clock.
3858: if (after == QUOTE) {
3859: ++pos;
3860: // Fall through to append(ch)
3861: } else {
3862: if (groupingCount < 0) {
3863: subpart = 3; // quoted prefix subpart
3864: } else {
3865: // Transition to suffix subpart
3866: subpart = 2; // suffix subpart
3867: affix = suffix;
3868: sub0Limit = pos--;
3869: }
3870: continue;
3871: }
3872: }
3873: }
3874:
3875: if (decimalPos >= 0) {
3876: patternError(
3877: "Grouping separator after decimal",
3878: pattern);
3879: }
3880: groupingCount2 = groupingCount;
3881: groupingCount = 0;
3882: } else if (ch == decimalSeparator) {
3883: if (decimalPos >= 0) {
3884: patternError("Multiple decimal separators",
3885: pattern);
3886: }
3887: // Intentionally incorporate the digitRightCount,
3888: // even though it is illegal for this to be > 0
3889: // at this point. We check pattern syntax below.
3890: decimalPos = digitLeftCount + zeroDigitCount
3891: + digitRightCount;
3892: } else {
3893: if (pattern.regionMatches(pos, exponent, 0,
3894: exponent.length())) {
3895: if (expDigits >= 0) {
3896: patternError(
3897: "Multiple exponential symbols",
3898: pattern);
3899: }
3900: if (groupingCount >= 0) {
3901: patternError(
3902: "Grouping separator in exponential",
3903: pattern);
3904: }
3905: pos += exponent.length();
3906: // Check for positive prefix
3907: if (pos < pattern.length()
3908: && pattern.charAt(pos) == plus) {
3909: expSignAlways = true;
3910: ++pos;
3911: }
3912: // Use lookahead to parse out the exponential part of the
3913: // pattern, then jump into suffix subpart.
3914: expDigits = 0;
3915: while (pos < pattern.length()
3916: && pattern.charAt(pos) == zeroDigit) {
3917: ++expDigits;
3918: ++pos;
3919: }
3920:
3921: // 1. Require at least one mantissa pattern digit
3922: // 2. Disallow "#+ @" in mantissa
3923: // 3. Require at least one exponent pattern digit
3924: if (((digitLeftCount + zeroDigitCount) < 1 && (sigDigitCount + digitRightCount) < 1)
3925: || (sigDigitCount > 0 && digitLeftCount > 0)
3926: || expDigits < 1) {
3927: patternError("Malformed exponential",
3928: pattern);
3929: }
3930: }
3931: // Transition to suffix subpart
3932: subpart = 2; // suffix subpart
3933: affix = suffix;
3934: sub0Limit = pos--; // backup: for() will increment
3935: continue;
3936: }
3937: break;
3938: case 1: // Prefix subpart
3939: case 2: // Suffix subpart
3940: // Process the prefix / suffix characters
3941: // Process unquoted characters seen in prefix or suffix
3942: // subpart.
3943:
3944: // Several syntax characters implicitly begins the
3945: // next subpart if we are in the prefix; otherwise
3946: // they are illegal if unquoted.
3947: if (ch == digit || ch == groupingSeparator
3948: || ch == decimalSeparator
3949: || (ch >= zeroDigit && ch <= nineDigit)
3950: || ch == sigDigit) {
3951: // Any of these characters implicitly begins the
3952: // next subpart if we are in the prefix
3953: if (subpart == 1) { // prefix subpart
3954: subpart = 0; // pattern proper subpart
3955: sub0Start = pos--; // Reprocess this character
3956: continue;
3957: } else if (ch == QUOTE) {
3958: /*Bug 4212072
3959: process the Localized pattern like "'Fr. '#'##0.05;'Fr.-'#'##0.05"
3960: (Locale="CH", groupingSeparator == QUOTE)
3961: [Richard/GCL]
3962: */
3963: // A quote outside quotes indicates either the opening
3964: // quote or two quotes, which is a quote literal. That is,
3965: // we have the first quote in 'do' or o''clock.
3966: if ((pos + 1) < pattern.length()
3967: && pattern.charAt(pos + 1) == QUOTE) {
3968: ++pos;
3969: affix.append(ch);
3970: } else {
3971: subpart += 2; // open quote
3972: }
3973: continue;
3974: }
3975: patternError("Unquoted special character '"
3976: + ch + '\'', pattern);
3977: } else if (ch == CURRENCY_SIGN) {
3978: // Use lookahead to determine if the currency sign is
3979: // doubled or not.
3980: boolean doubled = (pos + 1) < pattern.length()
3981: && pattern.charAt(pos + 1) == CURRENCY_SIGN;
3982: /*Bug 4212072
3983: To meet the need of expandAffix(String, StirngBuffer)
3984: [Richard/GCL]
3985: */
3986: if (doubled) {
3987: ++pos; // Skip over the doubled character
3988: affix.append(ch); // append two: one here, one below
3989: }
3990: isCurrency = true;
3991: // Fall through to append(ch)
3992: } else if (ch == QUOTE) {
3993: // A quote outside quotes indicates either the opening
3994: // quote or two quotes, which is a quote literal. That is,
3995: // we have the first quote in 'do' or o''clock.
3996: if ((pos + 1) < pattern.length()
3997: && pattern.charAt(pos + 1) == QUOTE) {
3998: ++pos;
3999: affix.append(ch); // append two: one here, one below
4000: } else {
4001: subpart += 2; // open quote
4002: }
4003: // Fall through to append(ch)
4004: } else if (ch == separator) {
4005: // Don't allow separators in the prefix, and don't allow
4006: // separators in the second pattern (part == 1).
4007: if (subpart == 1 || part == 1) {
4008: patternError("Unquoted special character '"
4009: + ch + '\'', pattern);
4010: }
4011: sub2Limit = pos++;
4012: break PARTLOOP; // Go to next part
4013: } else if (ch == percent || ch == perMill) {
4014: // Next handle characters which are appended directly.
4015: if (multiplier != 1) {
4016: patternError(
4017: "Too many percent/permille characters",
4018: pattern);
4019: }
4020: multiplier = (ch == percent) ? 100 : 1000;
4021: // Convert to non-localized pattern
4022: ch = (ch == percent) ? PATTERN_PERCENT
4023: : PATTERN_PER_MILLE;
4024: // Fall through to append(ch)
4025: } else if (ch == minus) {
4026: // Convert to non-localized pattern
4027: ch = PATTERN_MINUS;
4028: // Fall through to append(ch)
4029: } else if (ch == padEscape) {
4030: if (padPos >= 0) {
4031: patternError("Multiple pad specifiers",
4032: pattern);
4033: }
4034: if ((pos + 1) == pattern.length()) {
4035: patternError("Invalid pad specifier",
4036: pattern);
4037: }
4038: padPos = pos++; // Advance past pad char
4039: padChar = pattern.charAt(pos);
4040: continue;
4041: }
4042: affix.append(ch);
4043: break;
4044: case 3: // Prefix subpart, in quote
4045: case 4: // Suffix subpart, in quote
4046: // A quote within quotes indicates either the closing
4047: // quote or two quotes, which is a quote literal. That is,
4048: // we have the second quote in 'do' or 'don''t'.
4049: if (ch == QUOTE) {
4050: if ((pos + 1) < pattern.length()
4051: && pattern.charAt(pos + 1) == QUOTE) {
4052: ++pos;
4053: affix.append(ch);
4054: } else {
4055: subpart -= 2; // close quote
4056: }
4057: // Fall through to append(ch)
4058: }
4059: // NOTE: In ICU 2.2 there was code here to parse quoted
4060: // percent and permille characters _within quotes_ and give
4061: // them special meaning. This is incorrect, since quoted
4062: // characters are literals without special meaning.
4063: affix.append(ch);
4064: break;
4065: }
4066: }
4067:
4068: if (subpart == 3 || subpart == 4) {
4069: patternError("Unterminated quote", pattern);
4070: }
4071:
4072: if (sub0Limit == 0) {
4073: sub0Limit = pattern.length();
4074: }
4075:
4076: if (sub2Limit == 0) {
4077: sub2Limit = pattern.length();
4078: }
4079:
4080: /* Handle patterns with no '0' pattern character. These patterns
4081: * are legal, but must be recodified to make sense. "##.###" ->
4082: * "#0.###". ".###" -> ".0##".
4083: *
4084: * We allow patterns of the form "####" to produce a zeroDigitCount
4085: * of zero (got that?); although this seems like it might make it
4086: * possible for format() to produce empty strings, format() checks
4087: * for this condition and outputs a zero digit in this situation.
4088: * Having a zeroDigitCount of zero yields a minimum integer digits
4089: * of zero, which allows proper round-trip patterns. We don't want
4090: * "#" to become "#0" when toPattern() is called (even though that's
4091: * what it really is, semantically).
4092: */
4093: if (zeroDigitCount == 0 && sigDigitCount == 0
4094: && digitLeftCount > 0 && decimalPos >= 0) {
4095: // Handle "###.###" and "###." and ".###"
4096: int n = decimalPos;
4097: if (n == 0)
4098: ++n; // Handle ".###"
4099: digitRightCount = digitLeftCount - n;
4100: digitLeftCount = n - 1;
4101: zeroDigitCount = 1;
4102: }
4103:
4104: // Do syntax checking on the digits, decimal points, and quotes.
4105: if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0)
4106: || (decimalPos >= 0 && (sigDigitCount > 0
4107: || decimalPos < digitLeftCount || decimalPos > (digitLeftCount + zeroDigitCount)))
4108: || groupingCount == 0
4109: || groupingCount2 == 0
4110: || (sigDigitCount > 0 && zeroDigitCount > 0)
4111: || subpart > 2) { // subpart > 2 == unmatched quote
4112: patternError("Malformed pattern", pattern);
4113: }
4114:
4115: // Make sure pad is at legal position before or after affix.
4116: if (padPos >= 0) {
4117: if (padPos == start) {
4118: padPos = PAD_BEFORE_PREFIX;
4119: } else if (padPos + 2 == sub0Start) {
4120: padPos = PAD_AFTER_PREFIX;
4121: } else if (padPos == sub0Limit) {
4122: padPos = PAD_BEFORE_SUFFIX;
4123: } else if (padPos + 2 == sub2Limit) {
4124: padPos = PAD_AFTER_SUFFIX;
4125: } else {
4126: patternError("Illegal pad position", pattern);
4127: }
4128: }
4129:
4130: if (part == 0) {
4131: // Set negative affixes temporarily to match the positive
4132: // affixes. Fix this up later after processing both parts.
4133: /*Bug 4212072
4134: To meet the need of expandAffix(String, StirngBuffer)
4135: [Richard/GCL]
4136: */
4137: posPrefixPattern = negPrefixPattern = prefix.toString();
4138: posSuffixPattern = negSuffixPattern = suffix.toString();
4139:
4140: useExponentialNotation = (expDigits >= 0);
4141: if (useExponentialNotation) {
4142: minExponentDigits = expDigits;
4143: exponentSignAlwaysShown = expSignAlways;
4144: }
4145: isCurrencyFormat = isCurrency;
4146: int digitTotalCount = digitLeftCount + zeroDigitCount
4147: + digitRightCount;
4148: // The effectiveDecimalPos is the position the decimal is at or
4149: // would be at if there is no decimal. Note that if
4150: // decimalPos<0, then digitTotalCount == digitLeftCount +
4151: // zeroDigitCount.
4152: int effectiveDecimalPos = decimalPos >= 0 ? decimalPos
4153: : digitTotalCount;
4154: boolean useSigDig = (sigDigitCount > 0);
4155: setSignificantDigitsUsed(useSigDig);
4156: if (useSigDig) {
4157: setMinimumSignificantDigits(sigDigitCount);
4158: setMaximumSignificantDigits(sigDigitCount
4159: + digitRightCount);
4160: } else {
4161: int minInt = effectiveDecimalPos - digitLeftCount;
4162: setMinimumIntegerDigits(minInt);
4163: /*Upper limit on integer and fraction digits for a Java double
4164: [Richard/GCL]
4165: */
4166: setMaximumIntegerDigits(useExponentialNotation ? digitLeftCount
4167: + minInt
4168: : DOUBLE_INTEGER_DIGITS);
4169: setMaximumFractionDigits(decimalPos >= 0 ? (digitTotalCount - decimalPos)
4170: : 0);
4171: setMinimumFractionDigits(decimalPos >= 0 ? (digitLeftCount
4172: + zeroDigitCount - decimalPos)
4173: : 0);
4174: }
4175: setGroupingUsed(groupingCount > 0);
4176: this .groupingSize = (groupingCount > 0) ? groupingCount
4177: : 0;
4178: this .groupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount) ? groupingCount2
4179: : 0;
4180: this .multiplier = multiplier;
4181: setDecimalSeparatorAlwaysShown(decimalPos == 0
4182: || decimalPos == digitTotalCount);
4183: if (padPos >= 0) {
4184: padPosition = padPos;
4185: formatWidth = sub0Limit - sub0Start; // to be fixed up below
4186: pad = padChar;
4187: } else {
4188: formatWidth = 0;
4189: }
4190: if (incrementVal != 0) {
4191: // BigDecimal scale cannot be negative (even though
4192: // this makes perfect sense), so we need to handle this.
4193: int scale = incrementPos - effectiveDecimalPos;
4194: roundingIncrementICU = BigDecimal.valueOf(
4195: incrementVal, scale > 0 ? scale : 0);
4196: if (scale < 0) {
4197: roundingIncrementICU = roundingIncrementICU
4198: .movePointRight(-scale);
4199: }
4200: setRoundingDouble();
4201: roundingMode = BigDecimal.ROUND_HALF_EVEN;
4202: } else {
4203: setRoundingIncrement((BigDecimal) null);
4204: }
4205: } else {
4206: /*Bug 4212072
4207: To meet the need of expandAffix(String, StirngBuffer)
4208: [Richard/GCL]
4209: */
4210: negPrefixPattern = prefix.toString();
4211: negSuffixPattern = suffix.toString();
4212: gotNegative = true;
4213: }
4214: }
4215:
4216: /*Bug 4140009
4217: Process the empty pattern
4218: [Richard/GCL]
4219: */
4220: if (pattern.length() == 0) {
4221: posPrefixPattern = posSuffixPattern = "";
4222: setMinimumIntegerDigits(0);
4223: setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
4224: setMinimumFractionDigits(0);
4225: setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
4226: }
4227:
4228: // If there was no negative pattern, or if the negative pattern is
4229: // identical to the positive pattern, then prepend the minus sign to the
4230: // positive pattern to form the negative pattern.
4231: /*Bug 4212072
4232: To meet the need of expandAffix(String, StirngBuffer)
4233: [Richard/GCL]
4234: */
4235: if (!gotNegative
4236: || (negPrefixPattern.equals(posPrefixPattern) && negSuffixPattern
4237: .equals(posSuffixPattern))) {
4238: negSuffixPattern = posSuffixPattern;
4239: negPrefixPattern = PATTERN_MINUS + posPrefixPattern;
4240: }
4241: /*Bug 4212072
4242: Update the affix strings accroding to symbols in order to keep
4243: the affix strings up to date.
4244: [Richard/GCL]
4245: */
4246: expandAffixes();
4247:
4248: // Now that we have the actual prefix and suffix, fix up formatWidth
4249: if (formatWidth > 0) {
4250: formatWidth += positivePrefix.length()
4251: + positiveSuffix.length();
4252: }
4253:
4254: setLocale(null, null);
4255: }
4256:
4257: /**
4258: * Centralizes the setting of the roundingDouble and roundingDoubleReciprocal.
4259: */
4260: private void setRoundingDouble() {
4261: if (roundingIncrementICU == null) {
4262: roundingDouble = 0.0d;
4263: roundingDoubleReciprocal = 0.0d;
4264: } else {
4265: roundingDouble = roundingIncrementICU.doubleValue();
4266: setRoundingDoubleReciprocal(BigDecimal.ONE.divide(
4267: roundingIncrementICU, BigDecimal.ROUND_HALF_EVEN)
4268: .doubleValue());
4269: }
4270: }
4271:
4272: private void patternError(String msg, String pattern) {
4273: throw new IllegalArgumentException(msg + " in pattern \""
4274: + pattern + '"');
4275: }
4276:
4277: /*Rewrite the following 4 "set" methods
4278: Upper limit on integer and fraction digits for a Java double
4279: [Richard/GCL]
4280: */
4281: /**
4282: * Sets the maximum number of digits allowed in the integer portion of a
4283: * number. This override limits the integer digit count to 309.
4284: * @see NumberFormat#setMaximumIntegerDigits
4285: * @stable ICU 2.0
4286: */
4287: public void setMaximumIntegerDigits(int newValue) {
4288: super .setMaximumIntegerDigits(Math.min(newValue,
4289: DOUBLE_INTEGER_DIGITS));
4290: }
4291:
4292: /**
4293: * Sets the minimum number of digits allowed in the integer portion of a
4294: * number. This override limits the integer digit count to 309.
4295: * @see NumberFormat#setMinimumIntegerDigits
4296: * @stable ICU 2.0
4297: */
4298: public void setMinimumIntegerDigits(int newValue) {
4299: super .setMinimumIntegerDigits(Math.min(newValue,
4300: DOUBLE_INTEGER_DIGITS));
4301: }
4302:
4303: /**
4304: * Returns the minimum number of significant digits that will be
4305: * displayed. This value has no effect unless areSignificantDigitsUsed()
4306: * returns true.
4307: * @return the fewest significant digits that will be shown
4308: * @stable ICU 3.0
4309: */
4310: public int getMinimumSignificantDigits() {
4311: return minSignificantDigits;
4312: }
4313:
4314: /**
4315: * Returns the maximum number of significant digits that will be
4316: * displayed. This value has no effect unless areSignificantDigitsUsed()
4317: * returns true.
4318: * @return the most significant digits that will be shown
4319: * @stable ICU 3.0
4320: */
4321: public int getMaximumSignificantDigits() {
4322: return maxSignificantDigits;
4323: }
4324:
4325: /**
4326: * Sets the minimum number of significant digits that will be
4327: * displayed. If <code>min</code> is less than one then it is set
4328: * to one. If the maximum significant digits count is less than
4329: * <code>min</code>, then it is set to <code>min</code>. This
4330: * value has no effect unless areSignificantDigitsUsed() returns true.
4331: * @param min the fewest significant digits to be shown
4332: * @stable ICU 3.0
4333: */
4334: public void setMinimumSignificantDigits(int min) {
4335: if (min < 1) {
4336: min = 1;
4337: }
4338: // pin max sig dig to >= min
4339: int max = Math.max(maxSignificantDigits, min);
4340: minSignificantDigits = min;
4341: maxSignificantDigits = max;
4342: }
4343:
4344: /**
4345: * Sets the maximum number of significant digits that will be
4346: * displayed. If <code>max</code> is less than one then it is set
4347: * to one. If the minimum significant digits count is greater
4348: * than <code>max</code>, then it is set to <code>max</code>. This
4349: * value has no effect unless areSignificantDigitsUsed() returns true.
4350: * @param max the most significant digits to be shown
4351: * @stable ICU 3.0
4352: */
4353: public void setMaximumSignificantDigits(int max) {
4354: if (max < 1) {
4355: max = 1;
4356: }
4357: // pin min sig dig to 1..max
4358: int min = Math.min(minSignificantDigits, max);
4359: minSignificantDigits = min;
4360: maxSignificantDigits = max;
4361: }
4362:
4363: /**
4364: * Returns true if significant digits are in use or false if
4365: * integer and fraction digit counts are in use.
4366: * @return true if significant digits are in use
4367: * @stable ICU 3.0
4368: */
4369: public boolean areSignificantDigitsUsed() {
4370: return useSignificantDigits;
4371: }
4372:
4373: /**
4374: * Sets whether significant digits are in use, or integer and
4375: * fraction digit counts are in use.
4376: * @param useSignificantDigits true to use significant digits, or
4377: * false to use integer and fraction digit counts
4378: * @stable ICU 3.0
4379: */
4380: public void setSignificantDigitsUsed(boolean useSignificantDigits) {
4381: this .useSignificantDigits = useSignificantDigits;
4382: }
4383:
4384: /**
4385: * Sets the <tt>Currency</tt> object used to display currency
4386: * amounts. This takes effect immediately, if this format is a
4387: * currency format. If this format is not a currency format, then
4388: * the currency object is used if and when this object becomes a
4389: * currency format through the application of a new pattern.
4390: * @param theCurrency new currency object to use. Must not be
4391: * null.
4392: * @stable ICU 2.2
4393: */
4394: public void setCurrency(Currency theCurrency) {
4395: // If we are a currency format, then modify our affixes to
4396: // encode the currency symbol for the given currency in our
4397: // locale, and adjust the decimal digits and rounding for the
4398: // given currency.
4399:
4400: super .setCurrency(theCurrency);
4401: if (theCurrency != null) {
4402: boolean[] isChoiceFormat = new boolean[1];
4403: String s = theCurrency.getName(symbols.getULocale(),
4404: Currency.SYMBOL_NAME, isChoiceFormat);
4405: symbols.setCurrencySymbol(s);
4406: symbols.setInternationalCurrencySymbol(theCurrency
4407: .getCurrencyCode());
4408: }
4409:
4410: if (isCurrencyFormat) {
4411: if (theCurrency != null) {
4412: setRoundingIncrement(theCurrency.getRoundingIncrement());
4413:
4414: int d = theCurrency.getDefaultFractionDigits();
4415: setMinimumFractionDigits(d);
4416: setMaximumFractionDigits(d);
4417: }
4418: expandAffixes();
4419: }
4420: }
4421:
4422: /**
4423: * Returns the currency in effect for this formatter. Subclasses
4424: * should override this method as needed. Unlike getCurrency(),
4425: * this method should never return null.
4426: * @internal
4427: * @deprecated This API is ICU internal only.
4428: */
4429: protected Currency getEffectiveCurrency() {
4430: Currency c = getCurrency();
4431: if (c == null) {
4432: c = Currency.getInstance(symbols
4433: .getInternationalCurrencySymbol());
4434: }
4435: return c;
4436: }
4437:
4438: /**
4439: * Sets the maximum number of digits allowed in the fraction portion of a
4440: * number. This override limits the fraction digit count to 340.
4441: * @see NumberFormat#setMaximumFractionDigits
4442: * @stable ICU 2.0
4443: */
4444: public void setMaximumFractionDigits(int newValue) {
4445: super .setMaximumFractionDigits(Math.min(newValue,
4446: DOUBLE_FRACTION_DIGITS));
4447: }
4448:
4449: /**
4450: * Sets the minimum number of digits allowed in the fraction portion of a
4451: * number. This override limits the fraction digit count to 340.
4452: * @see NumberFormat#setMinimumFractionDigits
4453: * @stable ICU 2.0
4454: */
4455: public void setMinimumFractionDigits(int newValue) {
4456: super .setMinimumFractionDigits(Math.min(newValue,
4457: DOUBLE_FRACTION_DIGITS));
4458: }
4459:
4460: /**
4461: * Sets whether {@link #parse(String, ParsePosition)} method returns BigDecimal.
4462: * The default value is false.
4463: * @param value true if {@link #parse(String, ParsePosition)} method returns
4464: * BigDecimal.
4465: * @stable ICU 3.6
4466: */
4467: public void setParseBigDecimal(boolean value) {
4468: parseBigDecimal = value;
4469: }
4470:
4471: /**
4472: * Returns whether {@link #parse(String, ParsePosition)} method returns BigDecimal.
4473: * @return true if {@link #parse(String, ParsePosition)} method returns BigDecimal.
4474: * @stable ICU 3.6
4475: */
4476: public boolean isParseBigDecimal() {
4477: return parseBigDecimal;
4478: }
4479:
4480: //#ifndef FOUNDATION
4481: private void writeObject(ObjectOutputStream stream)
4482: throws IOException, ClassNotFoundException {
4483: // Doug, do we need this anymore?
4484: // if (roundingIncrementICU != null) {
4485: // roundingIncrement = roundingIncrementICU.toBigDecimal();
4486: // }
4487:
4488: stream.defaultWriteObject();
4489: }
4490:
4491: //#endif
4492:
4493: /**
4494: * First, read the default serializable fields from the stream. Then
4495: * if <code>serialVersionOnStream</code> is less than 1, indicating that
4496: * the stream was written by JDK 1.1, initialize <code>useExponentialNotation</code>
4497: * to false, since it was not present in JDK 1.1.
4498: * Finally, set serialVersionOnStream back to the maximum allowed value so that
4499: * default serialization will work properly if this object is streamed out again.
4500: */
4501: private void readObject(ObjectInputStream stream)
4502: throws IOException, ClassNotFoundException {
4503: stream.defaultReadObject();
4504: /*Bug 4185761 validate fields
4505: [Richard/GCL]
4506: */
4507: // We only need to check the maximum counts because NumberFormat
4508: // .readObject has already ensured that the maximum is greater than the
4509: // minimum count.
4510: /*Commented for compatibility with previous version, and reserved for further use
4511: if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
4512: getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
4513: throw new InvalidObjectException("Digit count out of range");
4514: }*/
4515: /* Truncate the maximumIntegerDigits to DOUBLE_INTEGER_DIGITS and maximumFractionDigits
4516: * to DOUBLE_FRACTION_DIGITS
4517: */
4518: if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS) {
4519: setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
4520: }
4521: if (getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
4522: setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
4523: }
4524: if (serialVersionOnStream < 2) {
4525: exponentSignAlwaysShown = false;
4526: setInternalRoundingIncrement(null);
4527: setRoundingDouble();
4528: roundingMode = BigDecimal.ROUND_HALF_EVEN;
4529: formatWidth = 0;
4530: pad = ' ';
4531: padPosition = PAD_BEFORE_PREFIX;
4532: if (serialVersionOnStream < 1) {
4533: // Didn't have exponential fields
4534: useExponentialNotation = false;
4535: }
4536: }
4537: if (serialVersionOnStream < 3) {
4538: // Versions prior to 3 do not store a currency object.
4539: // Create one to match the DecimalFormatSymbols object.
4540: setCurrencyForSymbols();
4541: }
4542: serialVersionOnStream = currentSerialVersion;
4543: digitList = new DigitList();
4544:
4545: //#ifndef FOUNDATION
4546: if (roundingIncrement != null) {
4547: setInternalRoundingIncrement(new BigDecimal(
4548: roundingIncrement));
4549: setRoundingDouble();
4550: }
4551: //#endif
4552: }
4553:
4554: private void setInternalRoundingIncrement(BigDecimal value) {
4555: roundingIncrementICU = value;
4556: //#ifndef FOUNDATION
4557: roundingIncrement = value == null ? null : value.toBigDecimal();
4558: //#endif
4559: }
4560:
4561: //----------------------------------------------------------------------
4562: // INSTANCE VARIABLES
4563: //----------------------------------------------------------------------
4564:
4565: private transient DigitList digitList = new DigitList();
4566:
4567: /**
4568: * The symbol used as a prefix when formatting positive numbers, e.g. "+".
4569: *
4570: * @serial
4571: * @see #getPositivePrefix
4572: */
4573: private String positivePrefix = "";
4574:
4575: /**
4576: * The symbol used as a suffix when formatting positive numbers.
4577: * This is often an empty string.
4578: *
4579: * @serial
4580: * @see #getPositiveSuffix
4581: */
4582: private String positiveSuffix = "";
4583:
4584: /**
4585: * The symbol used as a prefix when formatting negative numbers, e.g. "-".
4586: *
4587: * @serial
4588: * @see #getNegativePrefix
4589: */
4590: private String negativePrefix = "-";
4591:
4592: /**
4593: * The symbol used as a suffix when formatting negative numbers.
4594: * This is often an empty string.
4595: *
4596: * @serial
4597: * @see #getNegativeSuffix
4598: */
4599: private String negativeSuffix = "";
4600:
4601: /**
4602: * The prefix pattern for non-negative numbers. This variable corresponds
4603: * to <code>positivePrefix</code>.
4604: *
4605: * <p>This pattern is expanded by the method <code>expandAffix()</code> to
4606: * <code>positivePrefix</code> to update the latter to reflect changes in
4607: * <code>symbols</code>. If this variable is <code>null</code> then
4608: * <code>positivePrefix</code> is taken as a literal value that does not
4609: * change when <code>symbols</code> changes. This variable is always
4610: * <code>null</code> for <code>DecimalFormat</code> objects older than
4611: * stream version 2 restored from stream.
4612: *
4613: * @serial
4614: */
4615: //[Richard/GCL]
4616: private String posPrefixPattern;
4617:
4618: /**
4619: * The suffix pattern for non-negative numbers. This variable corresponds
4620: * to <code>positiveSuffix</code>. This variable is analogous to
4621: * <code>posPrefixPattern</code>; see that variable for further
4622: * documentation.
4623: *
4624: * @serial
4625: */
4626: //[Richard/GCL]
4627: private String posSuffixPattern;
4628:
4629: /**
4630: * The prefix pattern for negative numbers. This variable corresponds
4631: * to <code>negativePrefix</code>. This variable is analogous to
4632: * <code>posPrefixPattern</code>; see that variable for further
4633: * documentation.
4634: *
4635: * @serial
4636: */
4637: //[Richard/GCL]
4638: private String negPrefixPattern;
4639:
4640: /**
4641: * The suffix pattern for negative numbers. This variable corresponds
4642: * to <code>negativeSuffix</code>. This variable is analogous to
4643: * <code>posPrefixPattern</code>; see that variable for further
4644: * documentation.
4645: *
4646: * @serial
4647: */
4648: //[Richard/GCL]
4649: private String negSuffixPattern;
4650:
4651: /**
4652: * Formatter for ChoiceFormat-based currency names. If this field
4653: * is not null, then delegate to it to format currency symbols.
4654: * @since ICU 2.6
4655: */
4656: private ChoiceFormat currencyChoice;
4657:
4658: /**
4659: * The multiplier for use in percent, permill, etc.
4660: *
4661: * @serial
4662: * @see #getMultiplier
4663: */
4664: private int multiplier = 1;
4665:
4666: /**
4667: * The number of digits between grouping separators in the integer
4668: * portion of a number. Must be greater than 0 if
4669: * <code>NumberFormat.groupingUsed</code> is true.
4670: *
4671: * @serial
4672: * @see #getGroupingSize
4673: * @see NumberFormat#isGroupingUsed
4674: */
4675: private byte groupingSize = 3; // invariant, > 0 if useThousands
4676:
4677: /**
4678: * The secondary grouping size. This is only used for Hindi
4679: * numerals, which use a primary grouping of 3 and a secondary
4680: * grouping of 2, e.g., "12,34,567". If this value is less than
4681: * 1, then secondary grouping is equal to the primary grouping.
4682: * [NEW]
4683: */
4684: private byte groupingSize2 = 0;
4685:
4686: /**
4687: * If true, forces the decimal separator to always appear in a formatted
4688: * number, even if the fractional part of the number is zero.
4689: *
4690: * @serial
4691: * @see #isDecimalSeparatorAlwaysShown
4692: */
4693: private boolean decimalSeparatorAlwaysShown = false;
4694:
4695: /**
4696: * True if this object represents a currency format. This determines
4697: * whether the monetary decimal separator is used instead of the normal one.
4698: */
4699: private transient boolean isCurrencyFormat = false;
4700:
4701: /**
4702: * The <code>DecimalFormatSymbols</code> object used by this format.
4703: * It contains the symbols used to format numbers, e.g. the grouping separator,
4704: * decimal separator, and so on.
4705: *
4706: * @serial
4707: * @see #setDecimalFormatSymbols
4708: * @see DecimalFormatSymbols
4709: */
4710: private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
4711:
4712: /**
4713: * True to use significant digits rather than integer and fraction
4714: * digit counts.
4715: * @serial
4716: * @since ICU 3.0
4717: */
4718: private boolean useSignificantDigits = false;
4719:
4720: /**
4721: * The minimum number of significant digits to show. Must be >= 1
4722: * and <= maxSignificantDigits. Ignored unless
4723: * useSignificantDigits == true.
4724: * @serial
4725: * @since ICU 3.0
4726: */
4727: private int minSignificantDigits = 1;
4728:
4729: /**
4730: * The maximum number of significant digits to show. Must be >=
4731: * minSignficantDigits. Ignored unless useSignificantDigits ==
4732: * true.
4733: * @serial
4734: * @since ICU 3.0
4735: */
4736: private int maxSignificantDigits = 6;
4737:
4738: /**
4739: * True to force the use of exponential (i.e. scientific) notation when formatting
4740: * numbers.
4741: * <p>
4742: * Note that the JDK 1.2 public API provides no way to set this field,
4743: * even though it is supported by the implementation and the stream format.
4744: * The intent is that this will be added to the API in the future.
4745: *
4746: * @serial
4747: */
4748: private boolean useExponentialNotation; // Newly persistent in JDK 1.2
4749:
4750: /**
4751: * The minimum number of digits used to display the exponent when a number is
4752: * formatted in exponential notation. This field is ignored if
4753: * <code>useExponentialNotation</code> is not true.
4754: * <p>
4755: * Note that the JDK 1.2 public API provides no way to set this field,
4756: * even though it is supported by the implementation and the stream format.
4757: * The intent is that this will be added to the API in the future.
4758: *
4759: * @serial
4760: */
4761: private byte minExponentDigits; // Newly persistent in JDK 1.2
4762:
4763: /**
4764: * <strong><font face=helvetica color=red>NEW</font></strong>
4765: * If true, the exponent is always prefixed with either the plus
4766: * sign or the minus sign. Otherwise, only negative exponents are
4767: * prefixed with the minus sign. This has no effect unless
4768: * <code>useExponentialNotation</code> is true.
4769: * @serial
4770: * @since AlphaWorks NumberFormat
4771: */
4772: private boolean exponentSignAlwaysShown = false;
4773:
4774: //#ifndef FOUNDATION
4775: /**
4776: * <strong><font face=helvetica color=red>NEW</font></strong>
4777: * The value to which numbers are rounded during formatting. For example,
4778: * if the rounding increment is 0.05, then 13.371 would be formatted as
4779: * 13.350, assuming 3 fraction digits. Has the value <code>null</code> if
4780: * rounding is not in effect, or a positive value if rounding is in effect.
4781: * Default value <code>null</code>.
4782: * @serial
4783: * @since AlphaWorks NumberFormat
4784: */
4785: // Note: this is kept in sync with roundingIncrementICU.
4786: // it is only kept around to avoid a conversion when formatting a java.math.BigDecimal
4787: private java.math.BigDecimal roundingIncrement = null;
4788: //#endif
4789:
4790: /**
4791: * <strong><font face=helvetica color=red>NEW</font></strong>
4792: * The value to which numbers are rounded during formatting. For example,
4793: * if the rounding increment is 0.05, then 13.371 would be formatted as
4794: * 13.350, assuming 3 fraction digits. Has the value <code>null</code> if
4795: * rounding is not in effect, or a positive value if rounding is in effect.
4796: * Default value <code>null</code>.
4797: * WARNING: the roundingIncrement value is the one serialized.
4798: * @serial
4799: * @since AlphaWorks NumberFormat
4800: */
4801: private transient BigDecimal roundingIncrementICU = null;
4802:
4803: /**
4804: * <strong><font face=helvetica color=red>NEW</font></strong>
4805: * The rounding increment as a double. If this value is <= 0, then no
4806: * rounding is done. This value is
4807: * <code>roundingIncrementICU.doubleValue()</code>. Default value 0.0.
4808: */
4809: private transient double roundingDouble = 0.0;
4810:
4811: /**
4812: * <strong><font face=helvetica color=red>NEW</font></strong>
4813: * If the roundingDouble is the reciprocal of an integer (the most common case!),
4814: * this is set to be that integer. Otherwise it is 0.0.
4815: */
4816: private transient double roundingDoubleReciprocal = 0.0;
4817:
4818: /**
4819: * <strong><font face=helvetica color=red>NEW</font></strong>
4820: * The rounding mode. This value controls any rounding operations which
4821: * occur when applying a rounding increment or when reducing the number of
4822: * fraction digits to satisfy a maximum fraction digits limit. The value
4823: * may assume any of the <code>BigDecimal</code> rounding mode values.
4824: * Default value <code>BigDecimal.ROUND_HALF_EVEN</code>.
4825: * @serial
4826: * @since AlphaWorks NumberFormat
4827: */
4828: private int roundingMode = BigDecimal.ROUND_HALF_EVEN;
4829:
4830: /**
4831: * <strong><font face=helvetica color=red>NEW</font></strong>
4832: * The padded format width, or zero if there is no padding. Must
4833: * be >= 0. Default value zero.
4834: * @serial
4835: * @since AlphaWorks NumberFormat
4836: */
4837: private int formatWidth = 0;
4838:
4839: /**
4840: * <strong><font face=helvetica color=red>NEW</font></strong>
4841: * The character used to pad the result of format to
4842: * <code>formatWidth</code>, if padding is in effect. Default value ' '.
4843: * @serial
4844: * @since AlphaWorks NumberFormat
4845: */
4846: private char pad = ' ';
4847:
4848: /**
4849: * <strong><font face=helvetica color=red>NEW</font></strong>
4850: * The position in the string at which the <code>pad</code> character
4851: * will be inserted, if padding is in effect. Must have a value from
4852: * <code>PAD_BEFORE_PREFIX</code> to <code>PAD_AFTER_SUFFIX</code>.
4853: * Default value <code>PAD_BEFORE_PREFIX</code>.
4854: * @serial
4855: * @since AlphaWorks NumberFormat
4856: */
4857: private int padPosition = PAD_BEFORE_PREFIX;
4858:
4859: /**
4860: * True if {@link #parse(String, ParsePosition)} to return BigDecimal
4861: * rather than Long, Double or BigDecimal except special values.
4862: * This property is introduced for J2SE 5 compatibility support.
4863: * @serial
4864: * @since ICU 3.6
4865: * @see #setParseBigDecimal(boolean)
4866: * @see #isParseBigDecimal()
4867: */
4868: private boolean parseBigDecimal = false;
4869:
4870: //----------------------------------------------------------------------
4871:
4872: static final int currentSerialVersion = 3;
4873:
4874: /**
4875: * The internal serial version which says which version was written
4876: * Possible values are:
4877: * <ul>
4878: * <li><b>0</b> (default): versions before JDK 1.2
4879: * <li><b>1</b>: version from JDK 1.2 and later, which includes the two new fields
4880: * <code>useExponentialNotation</code> and <code>minExponentDigits</code>.
4881: * <li><b>2</b>: version on AlphaWorks, which adds roundingMode, formatWidth,
4882: * pad, padPosition, exponentSignAlwaysShown, roundingIncrement.
4883: * <li><b>3</b>: ICU 2.2. Adds currency object.
4884: * </ul>
4885: * @serial */
4886: private int serialVersionOnStream = currentSerialVersion;
4887:
4888: //----------------------------------------------------------------------
4889: // CONSTANTS
4890: //----------------------------------------------------------------------
4891:
4892: /**
4893: * <strong><font face=helvetica color=red>NEW</font></strong>
4894: * Constant for <code>getPadPosition()</code> and
4895: * <code>setPadPosition()</code> specifying pad characters inserted before
4896: * the prefix.
4897: * @see #setPadPosition
4898: * @see #getPadPosition
4899: * @see #PAD_AFTER_PREFIX
4900: * @see #PAD_BEFORE_SUFFIX
4901: * @see #PAD_AFTER_SUFFIX
4902: * @stable ICU 2.0
4903: */
4904: public static final int PAD_BEFORE_PREFIX = 0;
4905:
4906: /**
4907: * <strong><font face=helvetica color=red>NEW</font></strong>
4908: * Constant for <code>getPadPosition()</code> and
4909: * <code>setPadPosition()</code> specifying pad characters inserted after
4910: * the prefix.
4911: * @see #setPadPosition
4912: * @see #getPadPosition
4913: * @see #PAD_BEFORE_PREFIX
4914: * @see #PAD_BEFORE_SUFFIX
4915: * @see #PAD_AFTER_SUFFIX
4916: * @stable ICU 2.0
4917: */
4918: public static final int PAD_AFTER_PREFIX = 1;
4919:
4920: /**
4921: * <strong><font face=helvetica color=red>NEW</font></strong>
4922: * Constant for <code>getPadPosition()</code> and
4923: * <code>setPadPosition()</code> specifying pad characters inserted before
4924: * the suffix.
4925: * @see #setPadPosition
4926: * @see #getPadPosition
4927: * @see #PAD_BEFORE_PREFIX
4928: * @see #PAD_AFTER_PREFIX
4929: * @see #PAD_AFTER_SUFFIX
4930: * @stable ICU 2.0
4931: */
4932: public static final int PAD_BEFORE_SUFFIX = 2;
4933:
4934: /**
4935: * <strong><font face=helvetica color=red>NEW</font></strong>
4936: * Constant for <code>getPadPosition()</code> and
4937: * <code>setPadPosition()</code> specifying pad characters inserted after
4938: * the suffix.
4939: * @see #setPadPosition
4940: * @see #getPadPosition
4941: * @see #PAD_BEFORE_PREFIX
4942: * @see #PAD_AFTER_PREFIX
4943: * @see #PAD_BEFORE_SUFFIX
4944: * @stable ICU 2.0
4945: */
4946: public static final int PAD_AFTER_SUFFIX = 3;
4947:
4948: // Constants for characters used in programmatic (unlocalized) patterns.
4949: private static final char PATTERN_ZERO_DIGIT = '0';
4950: private static final char PATTERN_GROUPING_SEPARATOR = ',';
4951: private static final char PATTERN_DECIMAL_SEPARATOR = '.';
4952: private static final char PATTERN_DIGIT = '#';
4953: static final char PATTERN_SIGNIFICANT_DIGIT = '@';
4954: static final char PATTERN_EXPONENT = 'E'; // [NEW]
4955: static final char PATTERN_PLUS_SIGN = '+'; // [NEW]
4956:
4957: // Affix
4958: private static final char PATTERN_PER_MILLE = '\u2030';
4959: private static final char PATTERN_PERCENT = '%';
4960: static final char PATTERN_PAD_ESCAPE = '*'; // [NEW]
4961: /*Bug 4212072
4962: To meet the need of expandAffix(String, StirngBuffer)
4963: [Richard/GCL]
4964: */
4965: private static final char PATTERN_MINUS = '-'; //[Richard/GCL]
4966:
4967: // Other
4968: private static final char PATTERN_SEPARATOR = ';';
4969:
4970: // Pad escape is package private to allow access by DecimalFormatSymbols.
4971: // Also plus sign. Also exponent.
4972:
4973: /**
4974: * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
4975: * is used in patterns and substitued with either the currency symbol,
4976: * or if it is doubled, with the international currency symbol. If the
4977: * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
4978: * replaced with the monetary decimal separator.
4979: *
4980: * The CURRENCY_SIGN is not localized.
4981: */
4982: private static final char CURRENCY_SIGN = '\u00A4';
4983:
4984: private static final char QUOTE = '\'';
4985:
4986: /* Upper limit on integer and fraction digits for a Java double
4987: [Richard/GCL]
4988: */
4989: static final int DOUBLE_INTEGER_DIGITS = 309;
4990: static final int DOUBLE_FRACTION_DIGITS = 340;
4991:
4992: /**
4993: * When someone turns on scientific mode, we assume that more than this
4994: * number of digits is due to flipping from some other mode that didn't
4995: * restrict the maximum, and so we force 1 integer digit. We don't bother
4996: * to track and see if someone is using exponential notation with more than
4997: * this number, it wouldn't make sense anyway, and this is just to make sure
4998: * that someone turning on scientific mode with default settings doesn't
4999: * end up with lots of zeroes.
5000: */
5001: static final int MAX_SCIENTIFIC_INTEGER_DIGITS = 8;
5002:
5003: //#ifdef FOUNDATION
5004: //## // we're not compatible with other versions, since we have no java.math.BigDecimal field
5005: //## private static final long serialVersionUID = 2;
5006: //#else
5007: // Proclaim JDK 1.1 serial compatibility.
5008: private static final long serialVersionUID = 864413376551465018L;
5009: //#endif
5010: private ArrayList attributes = new ArrayList();
5011: }
5012:
5013: //eof
|