2 *******************************************************************************
3 * Copyright (C) 1996-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.text;
9 import java.io.IOException;
10 import java.io.ObjectInputStream;
11 import java.io.ObjectOutputStream;
12 import java.math.BigInteger;
13 import java.text.AttributedCharacterIterator;
14 import java.text.AttributedString;
15 import java.text.ChoiceFormat;
16 import java.text.FieldPosition;
17 import java.text.Format;
18 import java.text.ParsePosition;
19 import java.util.ArrayList;
20 import java.util.HashSet;
21 import java.util.Iterator;
24 import com.ibm.icu.impl.ICUConfig;
25 import com.ibm.icu.impl.PatternProps;
26 import com.ibm.icu.impl.Utility;
27 import com.ibm.icu.lang.UCharacter;
28 import com.ibm.icu.math.BigDecimal;
29 import com.ibm.icu.math.MathContext;
30 import com.ibm.icu.text.PluralRules.FixedDecimal;
31 import com.ibm.icu.util.Currency;
32 import com.ibm.icu.util.CurrencyAmount;
33 import com.ibm.icu.util.ULocale;
34 import com.ibm.icu.util.ULocale.Category;
37 * {@icuenhanced java.text.DecimalFormat}.{@icu _usage_}
39 * <code>DecimalFormat</code> is a concrete subclass of {@link NumberFormat} that formats
40 * decimal numbers. It has a variety of features designed to make it possible to parse and
41 * format numbers in any locale, including support for Western, Arabic, or Indic digits.
42 * It also supports different flavors of numbers, including integers ("123"), fixed-point
43 * numbers ("123.4"), scientific notation ("1.23E4"), percentages ("12%"), and currency
44 * amounts ("$123.00", "USD123.00", "123.00 US dollars"). All of these flavors can be
47 * <p>To obtain a {@link NumberFormat} for a specific locale (including the default
48 * locale) call one of <code>NumberFormat</code>'s factory methods such as {@link
49 * NumberFormat#getInstance}. Do not call the <code>DecimalFormat</code> constructors
50 * directly, unless you know what you are doing, since the {@link NumberFormat} factory
51 * methods may return subclasses other than <code>DecimalFormat</code>. If you need to
52 * customize the format object, do something like this:
55 * NumberFormat f = NumberFormat.getInstance(loc);
56 * if (f instanceof DecimalFormat) {
57 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
58 * }</pre></blockquote>
60 * <p><strong>Example Usage</strong>
62 * Print out a number using the localized number, currency, and percent
63 * format for each locale.
66 * Locale[] locales = NumberFormat.getAvailableLocales();
67 * double myNumber = -1234.56;
68 * NumberFormat format;
69 * for (int j=0; j<3; ++j) {
70 * System.out.println("FORMAT");
71 * for (int i = 0; i < locales.length; ++i) {
72 * if (locales[i].getCountry().length() == 0) {
73 * // Skip language-only locales
76 * System.out.print(locales[i].getDisplayName());
79 * format = NumberFormat.getInstance(locales[i]); break;
81 * format = NumberFormat.getCurrencyInstance(locales[i]); break;
83 * format = NumberFormat.getPercentInstance(locales[i]); break;
86 * // Assume format is a DecimalFormat
87 * System.out.print(": " + ((DecimalFormat) format).toPattern()
88 * + " -> " + form.format(myNumber));
89 * } catch (Exception e) {}
91 * System.out.println(" -> " + format.parse(form.format(myNumber)));
92 * } catch (ParseException e) {}
94 * }</pre></blockquote>
96 * <p>Another example use getInstance(style).<br/>
97 * Print out a number using the localized number, currency, percent,
98 * scientific, integer, iso currency, and plural currency format for each locale.
101 * ULocale locale = new ULocale("en_US");
102 * double myNumber = 1234.56;
103 * for (int j=NumberFormat.NUMBERSTYLE; j<=NumberFormat.PLURALCURRENCYSTYLE; ++j) {
104 * NumberFormat format = NumberFormat.getInstance(locale, j);
106 * // Assume format is a DecimalFormat
107 * System.out.print(": " + ((DecimalFormat) format).toPattern()
108 * + " -> " + form.format(myNumber));
109 * } catch (Exception e) {}
111 * System.out.println(" -> " + format.parse(form.format(myNumber)));
112 * } catch (ParseException e) {}
113 * }</pre></blockquote>
117 * <p>A <code>DecimalFormat</code> consists of a <em>pattern</em> and a set of
118 * <em>symbols</em>. The pattern may be set directly using {@link #applyPattern}, or
119 * indirectly using other API methods which manipulate aspects of the pattern, such as the
120 * minimum number of integer digits. The symbols are stored in a {@link
121 * DecimalFormatSymbols} object. When using the {@link NumberFormat} factory methods, the
122 * pattern and symbols are read from ICU's locale data.
124 * <h4>Special Pattern Characters</h4>
126 * <p>Many characters in a pattern are taken literally; they are matched during parsing
127 * and output unchanged during formatting. Special characters, on the other hand, stand
128 * for other characters, strings, or classes of characters. For example, the '#'
129 * character is replaced by a localized digit. Often the replacement character is the
130 * same as the pattern character; in the U.S. locale, the ',' grouping character is
131 * replaced by ','. However, the replacement is still happening, and if the symbols are
132 * modified, the grouping character changes. Some special characters affect the behavior
133 * of the formatter by their presence; for example, if the percent character is seen, then
134 * the value is multiplied by 100 before being displayed.
136 * <p>To insert a special character in a pattern as a literal, that is, without any
137 * special meaning, the character must be quoted. There are some exceptions to this which
140 * <p>The characters listed here are used in non-localized patterns. Localized patterns
141 * use the corresponding characters taken from this formatter's {@link
142 * DecimalFormatSymbols} object instead, and these characters lose their special status.
143 * Two exceptions are the currency sign and quote, which are not localized.
146 * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
147 * location, localized, and meaning.">
148 * <tr bgcolor="#ccccff">
149 * <th align=left>Symbol
150 * <th align=left>Location
151 * <th align=left>Localized?
152 * <th align=left>Meaning
158 * <tr valign=top bgcolor="#eeeeff">
159 * <td><code>1-9</code>
162 * <td>'1' through '9' indicate rounding.
167 * <td>Significant digit
168 * <tr valign=top bgcolor="#eeeeff">
172 * <td>Digit, zero shows as absent
177 * <td>Decimal separator or monetary decimal separator
178 * <tr valign=top bgcolor="#eeeeff">
187 * <td>Grouping separator
188 * <tr valign=top bgcolor="#eeeeff">
192 * <td>Separates mantissa and exponent in scientific notation.
193 * <em>Need not be quoted in prefix or suffix.</em>
198 * <td>Prefix positive exponents with localized plus sign.
199 * <em>Need not be quoted in prefix or suffix.</em>
200 * <tr valign=top bgcolor="#eeeeff">
202 * <td>Subpattern boundary
204 * <td>Separates positive and negative subpatterns
207 * <td>Prefix or suffix
209 * <td>Multiply by 100 and show as percentage
210 * <tr valign=top bgcolor="#eeeeff">
211 * <td><code>\u2030</code>
212 * <td>Prefix or suffix
214 * <td>Multiply by 1000 and show as per mille
216 * <td><code>¤</code> (<code>\u00A4</code>)
217 * <td>Prefix or suffix
219 * <td>Currency sign, replaced by currency symbol. If
220 * doubled, replaced by international currency symbol.
221 * If tripled, replaced by currency plural names, for example,
222 * "US dollar" or "US dollars" for America.
223 * If present in a pattern, the monetary decimal separator
224 * is used instead of the decimal separator.
225 * <tr valign=top bgcolor="#eeeeff">
227 * <td>Prefix or suffix
229 * <td>Used to quote special characters in a prefix or suffix,
230 * for example, <code>"'#'#"</code> formats 123 to
231 * <code>"#123"</code>. To create a single quote
232 * itself, use two in a row: <code>"# o''clock"</code>.
235 * <td>Prefix or suffix boundary
237 * <td>Pad escape, precedes pad character
241 * <p>A <code>DecimalFormat</code> pattern contains a postive and negative subpattern, for
242 * example, "#,##0.00;(#,##0.00)". Each subpattern has a prefix, a numeric part, and a
243 * suffix. If there is no explicit negative subpattern, the negative subpattern is the
244 * localized minus sign prefixed to the positive subpattern. That is, "0.00" alone is
245 * equivalent to "0.00;-0.00". If there is an explicit negative subpattern, it serves
246 * only to specify the negative prefix and suffix; the number of digits, minimal digits,
247 * and other characteristics are ignored in the negative subpattern. That means that
248 * "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)".
250 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, thousands
251 * separators, decimal separators, etc. may be set to arbitrary values, and they will
252 * appear properly during formatting. However, care must be taken that the symbols and
253 * strings do not conflict, or parsing will be unreliable. For example, either the
254 * positive and negative prefixes or the suffixes must be distinct for {@link #parse} to
255 * be able to distinguish positive from negative values. Another example is that the
256 * decimal separator and thousands separator should be distinct characters, or parsing
257 * will be impossible.
259 * <p>The <em>grouping separator</em> is a character that separates clusters of integer
260 * digits to make large numbers more legible. It commonly used for thousands, but in some
261 * locales it separates ten-thousands. The <em>grouping size</em> is the number of digits
262 * between the grouping separators, such as 3 for "100,000,000" or 4 for "1 0000
263 * 0000". There are actually two different grouping sizes: One used for the least
264 * significant integer digits, the <em>primary grouping size</em>, and one used for all
265 * others, the <em>secondary grouping size</em>. In most locales these are the same, but
266 * sometimes they are different. For example, if the primary grouping interval is 3, and
267 * the secondary is 2, then this corresponds to the pattern "#,##,##0", and the number
268 * 123456789 is formatted as "12,34,56,789". If a pattern contains multiple grouping
269 * separators, the interval between the last one and the end of the integer defines the
270 * primary grouping size, and the interval between the last two defines the secondary
271 * grouping size. All others are ignored, so "#,##,###,####" == "###,###,####" ==
274 * <p>Illegal patterns, such as "#.#.#" or "#.###,###", will cause
275 * <code>DecimalFormat</code> to throw an {@link IllegalArgumentException} with a message
276 * that describes the problem.
278 * <h4>Pattern BNF</h4>
281 * pattern := subpattern (';' subpattern)?
282 * subpattern := prefix? number exponent? suffix?
283 * number := (integer ('.' fraction)?) | sigDigits
284 * prefix := '\u0000'..'\uFFFD' - specialCharacters
285 * suffix := '\u0000'..'\uFFFD' - specialCharacters
286 * integer := '#'* '0'* '0'
287 * fraction := '0'* '#'*
288 * sigDigits := '#'* '@' '@'* '#'*
289 * exponent := 'E' '+'? '0'* '0'
290 * padSpec := '*' padChar
291 * padChar := '\u0000'..'\uFFFD' - quote
294 * X* 0 or more instances of X
295 * X? 0 or 1 instances of X
297 * C..D any character from C up to D, inclusive
298 * S-T characters in S, except those in T
300 * The first subpattern is for positive numbers. The second (optional)
301 * subpattern is for negative numbers.
303 * <p>Not indicated in the BNF syntax above:
307 * <li>The grouping separator ',' can occur inside the integer and sigDigits
308 * elements, between any two pattern characters of that element, as long as the integer or
309 * sigDigits element is not followed by the exponent element.
311 * <li>Two grouping intervals are recognized: That between the decimal point and the first
312 * grouping symbol, and that between the first and second grouping symbols. These
313 * intervals are identical in most locales, but in some locales they differ. For example,
314 * the pattern "#,##,###" formats the number 123456789 as
315 * "12,34,56,789".
317 * <li>The pad specifier <code>padSpec</code> may appear before the prefix, after the
318 * prefix, before the suffix, after the suffix, or not at all.
320 * <li>In place of '0', the digits '1' through '9' may be used to indicate a rounding
327 * <p><code>DecimalFormat</code> parses all Unicode characters that represent decimal
328 * digits, as defined by {@link UCharacter#digit}. In addition,
329 * <code>DecimalFormat</code> also recognizes as digits the ten consecutive characters
330 * starting with the localized zero digit defined in the {@link DecimalFormatSymbols}
331 * object. During formatting, the {@link DecimalFormatSymbols}-based digits are output.
333 * <p>During parsing, grouping separators are ignored.
335 * <p>For currency parsing, the formatter is able to parse every currency style formats no
336 * matter which style the formatter is constructed with. For example, a formatter
337 * instance gotten from NumberFormat.getInstance(ULocale, NumberFormat.CURRENCYSTYLE) can
338 * parse formats such as "USD1.00" and "3.00 US dollars".
340 * <p>If {@link #parse(String, ParsePosition)} fails to parse a string, it returns
341 * <code>null</code> and leaves the parse position unchanged. The convenience method
342 * {@link #parse(String)} indicates parse failure by throwing a {@link
343 * java.text.ParseException}.
345 * <p>Parsing an extremely large or small absolute value (such as 1.0E10000 or 1.0E-10000)
346 * requires huge memory allocation for representing the parsed number. Such input may expose
347 * a risk of DoS attacks. To prevent huge memory allocation triggered by such inputs,
348 * <code>DecimalFormat</code> internally limits of maximum decimal digits to be 1000. Thus,
349 * an input string resulting more than 1000 digits in plain decimal representation (non-exponent)
350 * will be treated as either overflow (positive/negative infinite) or underflow (+0.0/-0.0).
352 * <h4>Formatting</h4>
354 * <p>Formatting is guided by several parameters, all of which can be specified either
355 * using a pattern or using the API. The following description applies to formats that do
356 * not use <a href="#sci">scientific notation</a> or <a href="#sigdig">significant
359 * <ul><li>If the number of actual integer digits exceeds the <em>maximum integer
360 * digits</em>, then only the least significant digits are shown. For example, 1997 is
361 * formatted as "97" if the maximum integer digits is set to 2.
363 * <li>If the number of actual integer digits is less than the <em>minimum integer
364 * digits</em>, then leading zeros are added. For example, 1997 is formatted as "01997"
365 * if the minimum integer digits is set to 5.
367 * <li>If the number of actual fraction digits exceeds the <em>maximum fraction
368 * digits</em>, then half-even rounding it performed to the maximum fraction digits. For
369 * example, 0.125 is formatted as "0.12" if the maximum fraction digits is 2. This
370 * behavior can be changed by specifying a rounding increment and a rounding mode.
372 * <li>If the number of actual fraction digits is less than the <em>minimum fraction
373 * digits</em>, then trailing zeros are added. For example, 0.125 is formatted as
374 * "0.1250" if the mimimum fraction digits is set to 4.
376 * <li>Trailing fractional zeros are not displayed if they occur <em>j</em> positions
377 * after the decimal, where <em>j</em> is less than the maximum fraction digits. For
378 * example, 0.10004 is formatted as "0.1" if the maximum fraction digits is four or less.
381 * <p><strong>Special Values</strong>
383 * <p><code>NaN</code> is represented as a single character, typically
384 * <code>\uFFFD</code>. This character is determined by the {@link
385 * DecimalFormatSymbols} object. This is the only value for which the prefixes and
386 * suffixes are not used.
388 * <p>Infinity is represented as a single character, typically <code>\u221E</code>,
389 * with the positive or negative prefixes and suffixes applied. The infinity character is
390 * determined by the {@link DecimalFormatSymbols} object.
392 * <a name="sci"><h4>Scientific Notation</h4></a>
394 * <p>Numbers in scientific notation are expressed as the product of a mantissa and a
395 * power of ten, for example, 1234 can be expressed as 1.234 x 10<sup>3</sup>. The
396 * mantissa is typically in the half-open interval [1.0, 10.0) or sometimes [0.0, 1.0),
397 * but it need not be. <code>DecimalFormat</code> supports arbitrary mantissas.
398 * <code>DecimalFormat</code> can be instructed to use scientific notation through the API
399 * or through the pattern. In a pattern, the exponent character immediately followed by
400 * one or more digit characters indicates scientific notation. Example: "0.###E0" formats
401 * the number 1234 as "1.234E3".
405 * <li>The number of digit characters after the exponent character gives the minimum
406 * exponent digit count. There is no maximum. Negative exponents are formatted using the
407 * localized minus sign, <em>not</em> the prefix and suffix from the pattern. This allows
408 * patterns such as "0.###E0 m/s". To prefix positive exponents with a localized plus
409 * sign, specify '+' between the exponent and the digits: "0.###E+0" will produce formats
410 * "1E+1", "1E+0", "1E-1", etc. (In localized patterns, use the localized plus sign
413 * <li>The minimum number of integer digits is achieved by adjusting the exponent.
414 * Example: 0.00123 formatted with "00.###E0" yields "12.3E-4". This only happens if
415 * there is no maximum number of integer digits. If there is a maximum, then the minimum
416 * number of integer digits is fixed at one.
418 * <li>The maximum number of integer digits, if present, specifies the exponent grouping.
419 * The most common use of this is to generate <em>engineering notation</em>, in which the
420 * exponent is a multiple of three, e.g., "##0.###E0". The number 12345 is formatted
421 * using "##0.####E0" as "12.345E3".
423 * <li>When using scientific notation, the formatter controls the digit counts using
424 * significant digits logic. The maximum number of significant digits limits the total
425 * number of integer and fraction digits that will be shown in the mantissa; it does not
426 * affect parsing. For example, 12345 formatted with "##0.##E0" is "12.3E3". See the
427 * section on significant digits for more details.
429 * <li>The number of significant digits shown is determined as follows: If
430 * areSignificantDigitsUsed() returns false, then the minimum number of significant digits
431 * shown is one, and the maximum number of significant digits shown is the sum of the
432 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is unaffected by the
433 * maximum integer digits. If this sum is zero, then all significant digits are shown.
434 * If areSignificantDigitsUsed() returns true, then the significant digit counts are
435 * specified by getMinimumSignificantDigits() and getMaximumSignificantDigits(). In this
436 * case, the number of integer digits is fixed at one, and there is no exponent grouping.
438 * <li>Exponential patterns may not contain grouping separators.
442 * <a name="sigdig"><h4>Significant Digits</h4></a>
444 * <code>DecimalFormat</code> has two ways of controlling how many digits are shows: (a)
445 * significant digits counts, or (b) integer and fraction digit counts. Integer and
446 * fraction digit counts are described above. When a formatter is using significant
447 * digits counts, the number of integer and fraction digits is not specified directly, and
448 * the formatter settings for these counts are ignored. Instead, the formatter uses
449 * however many integer and fraction digits are required to display the specified number
450 * of significant digits. Examples:
453 * <table border=0 cellspacing=3 cellpadding=0>
454 * <tr bgcolor="#ccccff">
455 * <th align=left>Pattern
456 * <th align=left>Minimum significant digits
457 * <th align=left>Maximum significant digits
458 * <th align=left>Number
459 * <th align=left>Output of format()
461 * <td><code>@@@</code>
465 * <td><code>12300</code>
466 * <tr valign=top bgcolor="#eeeeff">
467 * <td><code>@@@</code>
471 * <td><code>0.123</code>
473 * <td><code>@@##</code>
477 * <td><code>3.142</code>
478 * <tr valign=top bgcolor="#eeeeff">
479 * <td><code>@@##</code>
483 * <td><code>1.23</code>
489 * <li>Significant digit counts may be expressed using patterns that specify a minimum and
490 * maximum number of significant digits. These are indicated by the <code>'@'</code> and
491 * <code>'#'</code> characters. The minimum number of significant digits is the number of
492 * <code>'@'</code> characters. The maximum number of significant digits is the number of
493 * <code>'@'</code> characters plus the number of <code>'#'</code> characters following on
494 * the right. For example, the pattern <code>"@@@"</code> indicates exactly 3 significant
495 * digits. The pattern <code>"@##"</code> indicates from 1 to 3 significant digits.
496 * Trailing zero digits to the right of the decimal separator are suppressed after the
497 * minimum number of significant digits have been shown. For example, the pattern
498 * <code>"@##"</code> formats the number 0.1203 as <code>"0.12"</code>.
500 * <li>If a pattern uses significant digits, it may not contain a decimal separator, nor
501 * the <code>'0'</code> pattern character. Patterns such as <code>"@00"</code> or
502 * <code>"@.###"</code> are disallowed.
504 * <li>Any number of <code>'#'</code> characters may be prepended to the left of the
505 * leftmost <code>'@'</code> character. These have no effect on the minimum and maximum
506 * significant digits counts, but may be used to position grouping separators. For
507 * example, <code>"#,#@#"</code> indicates a minimum of one significant digits, a maximum
508 * of two significant digits, and a grouping size of three.
510 * <li>In order to enable significant digits formatting, use a pattern containing the
511 * <code>'@'</code> pattern character. Alternatively, call {@link
512 * #setSignificantDigitsUsed setSignificantDigitsUsed(true)}.
514 * <li>In order to disable significant digits formatting, use a pattern that does not
515 * contain the <code>'@'</code> pattern character. Alternatively, call {@link
516 * #setSignificantDigitsUsed setSignificantDigitsUsed(false)}.
518 * <li>The number of significant digits has no effect on parsing.
520 * <li>Significant digits may be used together with exponential notation. Such patterns
521 * are equivalent to a normal exponential pattern with a minimum and maximum integer digit
522 * count of one, a minimum fraction digit count of <code>getMinimumSignificantDigits() -
523 * 1</code>, and a maximum fraction digit count of <code>getMaximumSignificantDigits() -
524 * 1</code>. For example, the pattern <code>"@@###E0"</code> is equivalent to
525 * <code>"0.0###E0"</code>.
527 * <li>If signficant digits are in use, then the integer and fraction digit counts, as set
528 * via the API, are ignored. If significant digits are not in use, then the signficant
529 * digit counts, as set via the API, are ignored.
535 * <p><code>DecimalFormat</code> supports padding the result of {@link #format} to a
536 * specific width. Padding may be specified either through the API or through the pattern
537 * syntax. In a pattern the pad escape character, followed by a single pad character,
538 * causes padding to be parsed and formatted. The pad escape character is '*' in
539 * unlocalized patterns, and can be localized using {@link
540 * DecimalFormatSymbols#setPadEscape}. For example, <code>"$*x#,##0.00"</code> formats
541 * 123 to <code>"$xx123.00"</code>, and 1234 to <code>"$1,234.00"</code>.
545 * <li>When padding is in effect, the width of the positive subpattern, including prefix
546 * and suffix, determines the format width. For example, in the pattern <code>"* #0
547 * o''clock"</code>, the format width is 10.
549 * <li>The width is counted in 16-bit code units (Java <code>char</code>s).
551 * <li>Some parameters which usually do not matter have meaning when padding is used,
552 * because the pattern width is significant with padding. In the pattern "*
553 * ##,##,#,##0.##", the format width is 14. The initial characters "##,##," do not affect
554 * the grouping size or maximum integer digits, but they do affect the format width.
556 * <li>Padding may be inserted at one of four locations: before the prefix, after the
557 * prefix, before the suffix, or after the suffix. If padding is specified in any other
558 * location, {@link #applyPattern} throws an {@link IllegalArgumentException}. If there
559 * is no prefix, before the prefix and after the prefix are equivalent, likewise for the
562 * <li>When specified in a pattern, the 16-bit <code>char</code> immediately following the
563 * pad escape is the pad character. This may be any character, including a special pattern
564 * character. That is, the pad escape <em>escapes</em> the following character. If there
565 * is no character after the pad escape, then the pattern is illegal.
570 * <strong>Rounding</strong>
572 * <p><code>DecimalFormat</code> supports rounding to a specific increment. For example,
573 * 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the nearest 0.65 is 1.3. The
574 * rounding increment may be specified through the API or in a pattern. To specify a
575 * rounding increment in a pattern, include the increment in the pattern itself. "#,#50"
576 * specifies a rounding increment of 50. "#,##0.05" specifies a rounding increment of
581 * <li>Rounding only affects the string produced by formatting. It does not affect
582 * parsing or change any numerical values.
584 * <li>A <em>rounding mode</em> determines how values are rounded; see the {@link
585 * com.ibm.icu.math.BigDecimal} documentation for a description of the modes. Rounding
586 * increments specified in patterns use the default mode, {@link
587 * com.ibm.icu.math.BigDecimal#ROUND_HALF_EVEN}.
589 * <li>Some locales use rounding in their currency formats to reflect the smallest
590 * currency denomination.
592 * <li>In a pattern, digits '1' through '9' specify rounding, but otherwise behave
593 * identically to digit '0'.
597 * <h4>Synchronization</h4>
599 * <p><code>DecimalFormat</code> objects are not synchronized. Multiple threads should
600 * not access one formatter concurrently.
602 * @see java.text.Format
608 public class DecimalFormat extends NumberFormat {
611 * Creates a DecimalFormat using the default pattern and symbols for the default
612 * <code>FORMAT</code> locale. This is a convenient way to obtain a DecimalFormat when
613 * internationalization is not the main concern.
615 * <p>To obtain standard formats for a given locale, use the factory methods on
616 * NumberFormat such as getNumberInstance. These factories will return the most
617 * appropriate sub-class of NumberFormat for a given locale.
619 * @see NumberFormat#getInstance
620 * @see NumberFormat#getNumberInstance
621 * @see NumberFormat#getCurrencyInstance
622 * @see NumberFormat#getPercentInstance
623 * @see Category#FORMAT
626 public DecimalFormat() {
627 ULocale def = ULocale.getDefault(Category.FORMAT);
628 String pattern = getPattern(def, 0);
629 // Always applyPattern after the symbols are set
630 this.symbols = new DecimalFormatSymbols(def);
631 setCurrency(Currency.getInstance(def));
632 applyPatternWithoutExpandAffix(pattern, false);
633 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
634 currencyPluralInfo = new CurrencyPluralInfo(def);
635 // the exact pattern is not known until the plural count is known.
636 // so, no need to expand affix now.
638 expandAffixAdjustWidth(null);
643 * Creates a DecimalFormat from the given pattern and the symbols for the default
644 * <code>FORMAT</code> locale. This is a convenient way to obtain a DecimalFormat when
645 * internationalization is not the main concern.
647 * <p>To obtain standard formats for a given locale, use the factory methods on
648 * NumberFormat such as getNumberInstance. These factories will return the most
649 * appropriate sub-class of NumberFormat for a given locale.
651 * @param pattern A non-localized pattern string.
652 * @throws IllegalArgumentException if the given pattern is invalid.
653 * @see NumberFormat#getInstance
654 * @see NumberFormat#getNumberInstance
655 * @see NumberFormat#getCurrencyInstance
656 * @see NumberFormat#getPercentInstance
657 * @see Category#FORMAT
660 public DecimalFormat(String pattern) {
661 // Always applyPattern after the symbols are set
662 ULocale def = ULocale.getDefault(Category.FORMAT);
663 this.symbols = new DecimalFormatSymbols(def);
664 setCurrency(Currency.getInstance(def));
665 applyPatternWithoutExpandAffix(pattern, false);
666 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
667 currencyPluralInfo = new CurrencyPluralInfo(def);
669 expandAffixAdjustWidth(null);
674 * Creates a DecimalFormat from the given pattern and symbols. Use this constructor
675 * when you need to completely customize the behavior of the format.
677 * <p>To obtain standard formats for a given locale, use the factory methods on
678 * NumberFormat such as getInstance or getCurrencyInstance. If you need only minor
679 * adjustments to a standard format, you can modify the format returned by a
680 * NumberFormat factory method.
682 * @param pattern a non-localized pattern string
683 * @param symbols the set of symbols to be used
684 * @exception IllegalArgumentException if the given pattern is invalid
685 * @see NumberFormat#getInstance
686 * @see NumberFormat#getNumberInstance
687 * @see NumberFormat#getCurrencyInstance
688 * @see NumberFormat#getPercentInstance
689 * @see DecimalFormatSymbols
692 public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
693 createFromPatternAndSymbols(pattern, symbols);
696 private void createFromPatternAndSymbols(String pattern, DecimalFormatSymbols inputSymbols) {
697 // Always applyPattern after the symbols are set
698 symbols = (DecimalFormatSymbols) inputSymbols.clone();
699 setCurrencyForSymbols();
700 applyPatternWithoutExpandAffix(pattern, false);
701 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
702 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale());
704 expandAffixAdjustWidth(null);
709 * Creates a DecimalFormat from the given pattern, symbols, information used for
710 * currency plural format, and format style. Use this constructor when you need to
711 * completely customize the behavior of the format.
713 * <p>To obtain standard formats for a given locale, use the factory methods on
714 * NumberFormat such as getInstance or getCurrencyInstance.
716 * <p>If you need only minor adjustments to a standard format, you can modify the
717 * format returned by a NumberFormat factory method using the setters.
719 * <p>If you want to completely customize a decimal format, using your own
720 * DecimalFormatSymbols (such as group separators) and your own information for
721 * currency plural formatting (such as plural rule and currency plural patterns), you
722 * can use this constructor.
724 * @param pattern a non-localized pattern string
725 * @param symbols the set of symbols to be used
726 * @param infoInput the information used for currency plural format, including
727 * currency plural patterns and plural rules.
728 * @param style the decimal formatting style, it is one of the following values:
729 * NumberFormat.NUMBERSTYLE; NumberFormat.CURRENCYSTYLE; NumberFormat.PERCENTSTYLE;
730 * NumberFormat.SCIENTIFICSTYLE; NumberFormat.INTEGERSTYLE;
731 * NumberFormat.ISOCURRENCYSTYLE; NumberFormat.PLURALCURRENCYSTYLE;
734 public DecimalFormat(String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput,
736 CurrencyPluralInfo info = infoInput;
737 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
738 info = (CurrencyPluralInfo) infoInput.clone();
740 create(pattern, symbols, info, style);
743 private void create(String pattern, DecimalFormatSymbols inputSymbols, CurrencyPluralInfo info,
745 if (inputStyle != NumberFormat.PLURALCURRENCYSTYLE) {
746 createFromPatternAndSymbols(pattern, inputSymbols);
748 // Always applyPattern after the symbols are set
749 symbols = (DecimalFormatSymbols) inputSymbols.clone();
750 currencyPluralInfo = info;
751 // the pattern used in format is not fixed until formatting, in which, the
752 // number is known and will be used to pick the right pattern based on plural
753 // count. Here, set the pattern as the pattern of plural count == "other".
754 // For most locale, the patterns are probably the same for all plural
755 // count. If not, the right pattern need to be re-applied during format.
756 String currencyPluralPatternForOther =
757 currencyPluralInfo.getCurrencyPluralPattern("other");
758 applyPatternWithoutExpandAffix(currencyPluralPatternForOther, false);
759 setCurrencyForSymbols();
765 * Creates a DecimalFormat for currency plural format from the given pattern, symbols,
768 DecimalFormat(String pattern, DecimalFormatSymbols inputSymbols, int style) {
769 CurrencyPluralInfo info = null;
770 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
771 info = new CurrencyPluralInfo(inputSymbols.getULocale());
773 create(pattern, inputSymbols, info, style);
781 public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
782 return format(number, result, fieldPosition, false);
785 // See if number is negative.
786 // usage: isNegative(multiply(numberToBeFormatted));
787 private boolean isNegative(double number) {
788 // Detecting whether a double is negative is easy with the exception of the value
789 // -0.0. This is a double which has a zero mantissa (and exponent), but a negative
790 // sign bit. It is semantically distinct from a zero with a positive sign bit, and
791 // this distinction is important to certain kinds of computations. However, it's a
792 // little tricky to detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you
793 // may ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
794 // -Infinity. Proper detection of -0.0 is needed to deal with the issues raised by
795 // bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
796 return (number < 0.0) || (number == 0.0 && 1 / number < 0.0);
799 // Rounds the number and strips of the negative sign.
800 // usage: round(multiply(numberToBeFormatted))
801 private double round(double number) {
802 boolean isNegative = isNegative(number);
806 // Apply rounding after multiplier
807 if (roundingDouble > 0.0) {
808 // number = roundingDouble
809 // * round(number / roundingDouble, roundingMode, isNegative);
811 number, roundingDouble, roundingDoubleReciprocal, roundingMode,
817 // Multiplies given number by multipler (if there is one) returning the new
818 // number. If there is no multiplier, returns the number passed in unchanged.
819 private double multiply(double number) {
820 if (multiplier != 1) {
821 return number * multiplier;
826 // [Spark/CDL] The actual method to format number. If boolean value
827 // parseAttr == true, then attribute information will be recorded.
828 private StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition,
830 fieldPosition.setBeginIndex(0);
831 fieldPosition.setEndIndex(0);
833 if (Double.isNaN(number)) {
834 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
835 fieldPosition.setBeginIndex(result.length());
836 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
837 fieldPosition.setBeginIndex(result.length());
840 result.append(symbols.getNaN());
841 // [Spark/CDL] Add attribute for NaN here.
842 // result.append(symbols.getNaN());
844 addAttribute(Field.INTEGER, result.length() - symbols.getNaN().length(),
847 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
848 fieldPosition.setEndIndex(result.length());
849 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
850 fieldPosition.setEndIndex(result.length());
853 addPadding(result, fieldPosition, 0, 0);
857 // Do this BEFORE checking to see if value is negative or infinite and
859 number = multiply(number);
860 boolean isNegative = isNegative(number);
861 number = round(number);
863 if (Double.isInfinite(number)) {
864 int prefixLen = appendAffix(result, isNegative, true, parseAttr);
866 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
867 fieldPosition.setBeginIndex(result.length());
868 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
869 fieldPosition.setBeginIndex(result.length());
872 // [Spark/CDL] Add attribute for infinity here.
873 result.append(symbols.getInfinity());
875 addAttribute(Field.INTEGER, result.length() - symbols.getInfinity().length(),
878 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
879 fieldPosition.setEndIndex(result.length());
880 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
881 fieldPosition.setEndIndex(result.length());
884 int suffixLen = appendAffix(result, isNegative, false, parseAttr);
886 addPadding(result, fieldPosition, prefixLen, suffixLen);
890 // At this point we are guaranteed a nonnegative finite
892 synchronized (digitList) {
893 digitList.set(number, precision(false), !useExponentialNotation &&
894 !areSignificantDigitsUsed());
895 return subformat(number, result, fieldPosition, isNegative, false, parseAttr);
900 * This is a special function used by the CompactDecimalFormat subclass.
901 * It completes only the rounding portion of the formatting and returns
902 * the resulting double. CompactDecimalFormat uses the result to compute
903 * the plural form to use.
905 * @param number The number to format.
906 * @return The number rounded to the correct number of significant digits
907 * with negative sign stripped off.
912 double adjustNumberAsInFormatting(double number) {
913 if (Double.isNaN(number)) {
916 number = round(multiply(number));
917 if (Double.isInfinite(number)) {
920 return toDigitList(number).getDouble();
924 DigitList toDigitList(double number) {
925 DigitList result = new DigitList();
926 result.set(number, precision(false), false);
931 * This is a special function used by the CompactDecimalFormat subclass
932 * to determine if the number to be formatted is negative.
934 * @param number The number to format.
935 * @return True if number is negative.
940 boolean isNumberNegative(double number) {
941 if (Double.isNaN(number)) {
944 return isNegative(multiply(number));
948 * Round a double value to the nearest multiple of the given rounding increment,
949 * according to the given mode. This is equivalent to rounding value/roundingInc to
950 * the nearest integer, according to the given mode, and returning that integer *
951 * roundingInc. Note this is changed from the version in 2.4, since division of
952 * doubles have inaccuracies. jitterbug 1871.
955 * the absolute value of the number to be rounded
957 * the rounding increment
958 * @param roundingIncReciprocal
959 * if non-zero, is the
961 * a BigDecimal rounding mode
963 * true if the number to be rounded is negative
964 * @return the absolute value of the rounded result
966 private static double round(double number, double roundingInc, double roundingIncReciprocal,
967 int mode, boolean isNegative) {
969 double div = roundingIncReciprocal == 0.0 ? number / roundingInc : number *
970 roundingIncReciprocal;
972 // do the absolute cases first
975 case BigDecimal.ROUND_CEILING:
976 div = (isNegative ? Math.floor(div + epsilon) : Math.ceil(div - epsilon));
978 case BigDecimal.ROUND_FLOOR:
979 div = (isNegative ? Math.ceil(div - epsilon) : Math.floor(div + epsilon));
981 case BigDecimal.ROUND_DOWN:
982 div = (Math.floor(div + epsilon));
984 case BigDecimal.ROUND_UP:
985 div = (Math.ceil(div - epsilon));
987 case BigDecimal.ROUND_UNNECESSARY:
988 if (div != Math.floor(div)) {
989 throw new ArithmeticException("Rounding necessary");
994 // Handle complex cases, where the choice depends on the closer value.
996 // We figure out the distances to the two possible values, ceiling and floor.
997 // We then go for the diff that is smaller. Only if they are equal does the
1000 double ceil = Math.ceil(div);
1001 double ceildiff = ceil - div; // (ceil * roundingInc) - number;
1002 double floor = Math.floor(div);
1003 double floordiff = div - floor; // number - (floor * roundingInc);
1005 // Note that the diff values were those mapped back to the "normal" space by
1006 // using the roundingInc. I don't have access to the original author of the
1007 // code but suspect that that was to produce better result in edge cases
1008 // because of machine precision, rather than simply using the difference
1009 // between, say, ceil and div. However, it didn't work in all cases. Am
1010 // trying instead using an epsilon value.
1013 case BigDecimal.ROUND_HALF_EVEN:
1014 // We should be able to just return Math.rint(a), but this
1015 // doesn't work in some VMs.
1016 // if one is smaller than the other, take the corresponding side
1017 if (floordiff + epsilon < ceildiff) {
1019 } else if (ceildiff + epsilon < floordiff) {
1021 } else { // they are equal, so we want to round to whichever is even
1022 double testFloor = floor / 2;
1023 div = (testFloor == Math.floor(testFloor)) ? floor : ceil;
1026 case BigDecimal.ROUND_HALF_DOWN:
1027 div = ((floordiff <= ceildiff + epsilon) ? floor : ceil);
1029 case BigDecimal.ROUND_HALF_UP:
1030 div = ((ceildiff <= floordiff + epsilon) ? ceil : floor);
1033 throw new IllegalArgumentException("Invalid rounding mode: " + mode);
1036 number = roundingIncReciprocal == 0.0 ? div * roundingInc : div / roundingIncReciprocal;
1040 private static double epsilon = 0.00000000001;
1045 // [Spark/CDL] Delegate to format_long_StringBuffer_FieldPosition_boolean
1047 public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
1048 return format(number, result, fieldPosition, false);
1051 private StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition,
1052 boolean parseAttr) {
1053 fieldPosition.setBeginIndex(0);
1054 fieldPosition.setEndIndex(0);
1056 // If we are to do rounding, we need to move into the BigDecimal
1057 // domain in order to do divide/multiply correctly.
1058 if (actualRoundingIncrementICU != null) {
1059 return format(BigDecimal.valueOf(number), result, fieldPosition);
1062 boolean isNegative = (number < 0);
1066 // In general, long values always represent real finite numbers, so we don't have
1067 // to check for +/- Infinity or NaN. However, there is one case we have to be
1068 // careful of: The multiplier can push a number near MIN_VALUE or MAX_VALUE
1069 // outside the legal range. We check for this before multiplying, and if it
1070 // happens we use BigInteger instead.
1071 if (multiplier != 1) {
1072 boolean tooBig = false;
1073 if (number < 0) { // This can only happen if number == Long.MIN_VALUE
1074 long cutoff = Long.MIN_VALUE / multiplier;
1075 tooBig = (number <= cutoff); // number == cutoff can only happen if multiplier == -1
1077 long cutoff = Long.MAX_VALUE / multiplier;
1078 tooBig = (number > cutoff);
1082 // format_BigInteger_StringBuffer_FieldPosition_boolean instead
1083 // parseAttr is used to judge whether to synthesize attributes.
1084 return format(BigInteger.valueOf(isNegative ? -number : number), result,
1085 fieldPosition, parseAttr);
1089 number *= multiplier;
1090 synchronized (digitList) {
1091 digitList.set(number, precision(true));
1092 return subformat(number, result, fieldPosition, isNegative, true, parseAttr);
1097 * Formats a BigInteger number.
1102 public StringBuffer format(BigInteger number, StringBuffer result,
1103 FieldPosition fieldPosition) {
1104 return format(number, result, fieldPosition, false);
1107 private StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition,
1108 boolean parseAttr) {
1109 // If we are to do rounding, we need to move into the BigDecimal
1110 // domain in order to do divide/multiply correctly.
1111 if (actualRoundingIncrementICU != null) {
1112 return format(new BigDecimal(number), result, fieldPosition);
1115 if (multiplier != 1) {
1116 number = number.multiply(BigInteger.valueOf(multiplier));
1119 // At this point we are guaranteed a nonnegative finite
1121 synchronized (digitList) {
1122 digitList.set(number, precision(true));
1123 return subformat(number.intValue(), result, fieldPosition, number.signum() < 0, true,
1129 * Formats a BigDecimal number.
1134 public StringBuffer format(java.math.BigDecimal number, StringBuffer result,
1135 FieldPosition fieldPosition) {
1136 return format(number, result, fieldPosition, false);
1139 private StringBuffer format(java.math.BigDecimal number, StringBuffer result,
1140 FieldPosition fieldPosition,
1141 boolean parseAttr) {
1142 if (multiplier != 1) {
1143 number = number.multiply(java.math.BigDecimal.valueOf(multiplier));
1146 if (actualRoundingIncrement != null) {
1147 number = number.divide(actualRoundingIncrement, 0, roundingMode).multiply(actualRoundingIncrement);
1150 synchronized (digitList) {
1151 digitList.set(number, precision(false), !useExponentialNotation &&
1152 !areSignificantDigitsUsed());
1153 return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0,
1159 * Formats a BigDecimal number.
1164 public StringBuffer format(BigDecimal number, StringBuffer result,
1165 FieldPosition fieldPosition) {
1166 // This method is just a copy of the corresponding java.math.BigDecimal method
1167 // for now. It isn't very efficient since it must create a conversion object to
1168 // do math on the rounding increment. In the future we may try to clean this up,
1169 // or even better, limit our support to just one flavor of BigDecimal.
1170 if (multiplier != 1) {
1171 number = number.multiply(BigDecimal.valueOf(multiplier), mathContext);
1174 if (actualRoundingIncrementICU != null) {
1175 number = number.divide(actualRoundingIncrementICU, 0, roundingMode)
1176 .multiply(actualRoundingIncrementICU, mathContext);
1179 synchronized (digitList) {
1180 digitList.set(number, precision(false), !useExponentialNotation &&
1181 !areSignificantDigitsUsed());
1182 return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0,
1188 * Returns true if a grouping separator belongs at the given position, based on whether
1189 * grouping is in use and the values of the primary and secondary grouping interval.
1191 * @param pos the number of integer digits to the right of the current position. Zero
1192 * indicates the position after the rightmost integer digit.
1193 * @return true if a grouping character belongs at the current position.
1195 private boolean isGroupingPosition(int pos) {
1196 boolean result = false;
1197 if (isGroupingUsed() && (pos > 0) && (groupingSize > 0)) {
1198 if ((groupingSize2 > 0) && (pos > groupingSize)) {
1199 result = ((pos - groupingSize) % groupingSize2) == 0;
1201 result = pos % groupingSize == 0;
1208 * Return the number of fraction digits to display, or the total
1209 * number of digits for significant digit formats and exponential
1212 private int precision(boolean isIntegral) {
1213 if (areSignificantDigitsUsed()) {
1214 return getMaximumSignificantDigits();
1215 } else if (useExponentialNotation) {
1216 return getMinimumIntegerDigits() + getMaximumFractionDigits();
1218 return isIntegral ? 0 : getMaximumFractionDigits();
1222 private StringBuffer subformat(int number, StringBuffer result, FieldPosition fieldPosition,
1223 boolean isNegative, boolean isInteger, boolean parseAttr) {
1224 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
1225 // compute the plural category from the digitList plus other settings
1226 return subformat(currencyPluralInfo.select(getFixedDecimal(number)),
1227 result, fieldPosition, isNegative,
1228 isInteger, parseAttr);
1230 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
1235 * This is ugly, but don't see a better way to do it without major restructuring of the code.
1237 /*package*/ FixedDecimal getFixedDecimal(double number) {
1238 // get the visible fractions and the number of fraction digits.
1239 return getFixedDecimal(number, digitList);
1242 FixedDecimal getFixedDecimal(double number, DigitList dl) {
1243 int fractionalDigitsInDigitList = dl.count - dl.decimalAt;
1246 int maxFractionalDigits;
1247 int minFractionalDigits;
1248 if (useSignificantDigits) {
1249 maxFractionalDigits = maxSignificantDigits - dl.decimalAt;
1250 minFractionalDigits = minSignificantDigits - dl.decimalAt;
1251 if (minFractionalDigits < 0) {
1252 minFractionalDigits = 0;
1254 if (maxFractionalDigits < 0) {
1255 maxFractionalDigits = 0;
1258 maxFractionalDigits = getMaximumFractionDigits();
1259 minFractionalDigits = getMinimumFractionDigits();
1261 v = fractionalDigitsInDigitList;
1262 if (v < minFractionalDigits) {
1263 v = minFractionalDigits;
1264 } else if (v > maxFractionalDigits) {
1265 v = maxFractionalDigits;
1269 for (int i = Math.max(0, dl.decimalAt); i < dl.count; ++i) {
1271 f += (dl.digits[i] - '0');
1273 for (int i = v; i < fractionalDigitsInDigitList; ++i) {
1277 return new FixedDecimal(number, v, f);
1280 private StringBuffer subformat(double number, StringBuffer result, FieldPosition fieldPosition,
1282 boolean isInteger, boolean parseAttr) {
1283 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
1284 // compute the plural category from the digitList plus other settings
1285 return subformat(currencyPluralInfo.select(getFixedDecimal(number)),
1286 result, fieldPosition, isNegative,
1287 isInteger, parseAttr);
1289 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
1293 private StringBuffer subformat(String pluralCount, StringBuffer result, FieldPosition fieldPosition,
1294 boolean isNegative, boolean isInteger, boolean parseAttr) {
1295 // There are 2 ways to activate currency plural format: by applying a pattern with
1296 // 3 currency sign directly, or by instantiate a decimal formatter using
1297 // PLURALCURRENCYSTYLE. For both cases, the number of currency sign in the
1298 // pattern is 3. Even if the number of currency sign in the pattern is 3, it does
1299 // not mean we need to reset the pattern. For 1st case, we do not need to reset
1300 // pattern. For 2nd case, we might need to reset pattern, if the default pattern
1301 // (corresponding to plural count 'other') we use is different from the pattern
1302 // based on 'pluralCount'.
1304 // style is only valid when decimal formatter is constructed through
1305 // DecimalFormat(pattern, symbol, style)
1306 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
1307 // May need to reset pattern if the style is PLURALCURRENCYSTYLE.
1308 String currencyPluralPattern = currencyPluralInfo.getCurrencyPluralPattern(pluralCount);
1309 if (formatPattern.equals(currencyPluralPattern) == false) {
1310 applyPatternWithoutExpandAffix(currencyPluralPattern, false);
1313 // Expand the affix to the right name according to the plural rule. This is only
1314 // used for currency plural formatting. Currency plural name is not a fixed
1315 // static one, it is a dynamic name based on the currency plural count. So, the
1316 // affixes need to be expanded here. For other cases, the affix is a static one
1317 // based on pattern alone, and it is already expanded during applying pattern, or
1318 // setDecimalFormatSymbols, or setCurrency.
1319 expandAffixAdjustWidth(pluralCount);
1320 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr);
1324 * Complete the formatting of a finite number. On entry, the
1325 * digitList must be filled in with the correct digits.
1327 private StringBuffer subformat(StringBuffer result, FieldPosition fieldPosition,
1328 boolean isNegative, boolean isInteger, boolean parseAttr) {
1329 // NOTE: This isn't required anymore because DigitList takes care of this.
1331 // // The negative of the exponent represents the number of leading // zeros
1332 // between the decimal and the first non-zero digit, for // a value < 0.1 (e.g.,
1333 // for 0.00123, -fExponent == 2). If this // is more than the maximum fraction
1334 // digits, then we have an underflow // for the printed representation. We
1335 // recognize this here and set // the DigitList representation to zero in this
1338 // if (-digitList.decimalAt >= getMaximumFractionDigits())
1340 // digitList.count = 0;
1345 // Per bug 4147706, DecimalFormat must respect the sign of numbers which format as
1346 // zero. This allows sensible computations and preserves relations such as
1347 // signum(1/x) = signum(x), where x is +Infinity or -Infinity. Prior to this fix,
1348 // we always formatted zero values as if they were positive. Liu 7/6/98.
1349 if (digitList.isZero()) {
1350 digitList.decimalAt = 0; // Normalize
1353 int prefixLen = appendAffix(result, isNegative, true, parseAttr);
1355 if (useExponentialNotation) {
1356 subformatExponential(result, fieldPosition, parseAttr);
1358 subformatFixed(result, fieldPosition, isInteger, parseAttr);
1361 int suffixLen = appendAffix(result, isNegative, false, parseAttr);
1363 addPadding(result, fieldPosition, prefixLen, suffixLen);
1367 private void subformatFixed(StringBuffer result,
1368 FieldPosition fieldPosition,
1370 boolean parseAttr) {
1371 char [] digits = symbols.getDigitsLocal();
1373 char grouping = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ?
1374 symbols.getGroupingSeparator(): symbols.getMonetaryGroupingSeparator();
1375 char decimal = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ?
1376 symbols.getDecimalSeparator() : symbols.getMonetaryDecimalSeparator();
1377 boolean useSigDig = areSignificantDigitsUsed();
1378 int maxIntDig = getMaximumIntegerDigits();
1379 int minIntDig = getMinimumIntegerDigits();
1381 // [Spark/CDL] Record the integer start index.
1382 int intBegin = result.length();
1383 // Record field information for caller.
1384 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1385 fieldPosition.setBeginIndex(result.length());
1386 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
1387 fieldPosition.setBeginIndex(result.length());
1389 long fractionalDigits = 0;
1390 int fractionalDigitsCount = 0;
1391 boolean recordFractionDigits = false;
1394 int minSigDig = getMinimumSignificantDigits();
1395 int maxSigDig = getMaximumSignificantDigits();
1398 maxSigDig = Integer.MAX_VALUE;
1401 // Output the integer portion. Here 'count' is the total number of integer
1402 // digits we will display, including both leading zeros required to satisfy
1403 // getMinimumIntegerDigits, and actual digits present in the number.
1404 int count = useSigDig ? Math.max(1, digitList.decimalAt) : minIntDig;
1405 if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
1406 count = digitList.decimalAt;
1409 // Handle the case where getMaximumIntegerDigits() is smaller than the real
1410 // number of integer digits. If this is so, we output the least significant
1411 // max integer digits. For example, the value 1997 printed with 2 max integer
1412 // digits is just "97".
1414 int digitIndex = 0; // Index into digitList.fDigits[]
1415 if (count > maxIntDig && maxIntDig >= 0) {
1417 digitIndex = digitList.decimalAt - count;
1420 int sizeBeforeIntegerPart = result.length();
1421 for (i = count - 1; i >= 0; --i) {
1422 if (i < digitList.decimalAt && digitIndex < digitList.count
1423 && sigCount < maxSigDig) {
1424 // Output a real digit
1425 result.append(digits[digitList.getDigitValue(digitIndex++)]);
1428 // Output a zero (leading or trailing)
1429 result.append(digits[0]);
1435 // Output grouping separator if necessary.
1436 if (isGroupingPosition(i)) {
1437 result.append(grouping);
1438 // [Spark/CDL] Add grouping separator attribute here.
1440 // Length of grouping separator is 1.
1441 addAttribute(Field.GROUPING_SEPARATOR, result.length() - 1, result.length());
1446 // Record field information for caller.
1447 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1448 fieldPosition.setEndIndex(result.length());
1449 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
1450 fieldPosition.setEndIndex(result.length());
1453 // This handles the special case of formatting 0. For zero only, we count the
1454 // zero to the left of the decimal point as one signficant digit. Ordinarily we
1455 // do not count any leading 0's as significant. If the number we are formatting
1456 // is not zero, then either sigCount or digits.getCount() will be non-zero.
1457 if (sigCount == 0 && digitList.count == 0) {
1461 // Determine whether or not there are any printable fractional digits. If
1462 // we've used up the digits we know there aren't.
1463 boolean fractionPresent = (!isInteger && digitIndex < digitList.count)
1464 || (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0));
1466 // If there is no fraction present, and we haven't printed any integer digits,
1467 // then print a zero. Otherwise we won't print _any_ digits, and we won't be
1468 // able to parse this string.
1469 if (!fractionPresent && result.length() == sizeBeforeIntegerPart)
1470 result.append(digits[0]);
1471 // [Spark/CDL] Add attribute for integer part.
1473 addAttribute(Field.INTEGER, intBegin, result.length());
1475 // Output the decimal separator if we always do so.
1476 if (decimalSeparatorAlwaysShown || fractionPresent) {
1477 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) {
1478 fieldPosition.setBeginIndex(result.length());
1480 result.append(decimal);
1481 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) {
1482 fieldPosition.setEndIndex(result.length());
1484 // [Spark/CDL] Add attribute for decimal separator
1486 addAttribute(Field.DECIMAL_SEPARATOR, result.length() - 1, result.length());
1490 // Record field information for caller.
1491 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1492 fieldPosition.setBeginIndex(result.length());
1493 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
1494 fieldPosition.setBeginIndex(result.length());
1497 // [Spark/CDL] Record the begin index of fraction part.
1498 int fracBegin = result.length();
1499 recordFractionDigits = fieldPosition instanceof UFieldPosition;
1501 count = useSigDig ? Integer.MAX_VALUE : getMaximumFractionDigits();
1502 if (useSigDig && (sigCount == maxSigDig ||
1503 (sigCount >= minSigDig && digitIndex == digitList.count))) {
1506 for (i = 0; i < count; ++i) {
1507 // Here is where we escape from the loop. We escape if we've output the
1508 // maximum fraction digits (specified in the for expression above). We
1509 // also stop when we've output the minimum digits and either: we have an
1510 // integer, so there is no fractional stuff to display, or we're out of
1511 // significant digits.
1512 if (!useSigDig && i >= getMinimumFractionDigits() &&
1513 (isInteger || digitIndex >= digitList.count)) {
1517 // Output leading fractional zeros. These are zeros that come after the
1518 // decimal but before any significant digits. These are only output if
1519 // abs(number being formatted) < 1.0.
1520 if (-1 - i > (digitList.decimalAt - 1)) {
1521 result.append(digits[0]);
1522 if (recordFractionDigits) {
1523 ++fractionalDigitsCount;
1524 fractionalDigits *= 10;
1529 // Output a digit, if we have any precision left, or a zero if we
1530 // don't. We don't want to output noise digits.
1531 if (!isInteger && digitIndex < digitList.count) {
1532 byte digit = digitList.getDigitValue(digitIndex++);
1533 result.append(digits[digit]);
1534 if (recordFractionDigits) {
1535 ++fractionalDigitsCount;
1536 fractionalDigits *= 10;
1537 fractionalDigits += digit;
1540 result.append(digits[0]);
1541 if (recordFractionDigits) {
1542 ++fractionalDigitsCount;
1543 fractionalDigits *= 10;
1547 // If we reach the maximum number of significant digits, or if we output
1548 // all the real digits and reach the minimum, then we are done.
1550 if (useSigDig && (sigCount == maxSigDig ||
1551 (digitIndex == digitList.count && sigCount >= minSigDig))) {
1556 // Record field information for caller.
1557 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1558 fieldPosition.setEndIndex(result.length());
1559 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
1560 fieldPosition.setEndIndex(result.length());
1562 if (recordFractionDigits) {
1563 ((UFieldPosition) fieldPosition).setFractionDigits(fractionalDigitsCount, fractionalDigits);
1566 // [Spark/CDL] Add attribute information if necessary.
1567 if (parseAttr && (decimalSeparatorAlwaysShown || fractionPresent)) {
1568 addAttribute(Field.FRACTION, fracBegin, result.length());
1572 private void subformatExponential(StringBuffer result,
1573 FieldPosition fieldPosition,
1574 boolean parseAttr) {
1575 char [] digits = symbols.getDigitsLocal();
1576 char decimal = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ?
1577 symbols.getDecimalSeparator() : symbols.getMonetaryDecimalSeparator();
1578 boolean useSigDig = areSignificantDigitsUsed();
1579 int maxIntDig = getMaximumIntegerDigits();
1580 int minIntDig = getMinimumIntegerDigits();
1582 // Record field information for caller.
1583 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1584 fieldPosition.setBeginIndex(result.length());
1585 fieldPosition.setEndIndex(-1);
1586 } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1587 fieldPosition.setBeginIndex(-1);
1588 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
1589 fieldPosition.setBeginIndex(result.length());
1590 fieldPosition.setEndIndex(-1);
1591 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
1592 fieldPosition.setBeginIndex(-1);
1597 // the begin index of integer part
1598 // the end index of integer part
1599 // the begin index of fractional part
1600 int intBegin = result.length();
1605 maxIntDig = minIntDig = 1;
1606 minFracDig = getMinimumSignificantDigits() - 1;
1608 minFracDig = getMinimumFractionDigits();
1609 if (maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
1611 if (maxIntDig < minIntDig) {
1612 maxIntDig = minIntDig;
1615 if (maxIntDig > minIntDig) {
1619 long fractionalDigits = 0;
1620 int fractionalDigitsCount = 0;
1621 boolean recordFractionDigits = false;
1623 // Minimum integer digits are handled in exponential format by adjusting the
1624 // exponent. For example, 0.01234 with 3 minimum integer digits is "123.4E-4".
1626 // Maximum integer digits are interpreted as indicating the repeating
1627 // range. This is useful for engineering notation, in which the exponent is
1628 // restricted to a multiple of 3. For example, 0.01234 with 3 maximum integer
1629 // digits is "12.34e-3". If maximum integer digits are defined and are larger
1630 // than minimum integer digits, then minimum integer digits are ignored.
1632 int exponent = digitList.decimalAt;
1633 if (maxIntDig > 1 && maxIntDig != minIntDig) {
1634 // A exponent increment is defined; adjust to it.
1635 exponent = (exponent > 0) ? (exponent - 1) / maxIntDig : (exponent / maxIntDig) - 1;
1636 exponent *= maxIntDig;
1638 // No exponent increment is defined; use minimum integer digits.
1639 // If none is specified, as in "#E0", generate 1 integer digit.
1640 exponent -= (minIntDig > 0 || minFracDig > 0) ? minIntDig : 1;
1643 // We now output a minimum number of digits, and more if there are more
1644 // digits, up to the maximum number of digits. We place the decimal point
1645 // after the "integer" digits, which are the first (decimalAt - exponent)
1647 int minimumDigits = minIntDig + minFracDig;
1648 // The number of integer digits is handled specially if the number
1649 // is zero, since then there may be no digits.
1650 int integerDigits = digitList.isZero() ? minIntDig : digitList.decimalAt - exponent;
1651 int totalDigits = digitList.count;
1652 if (minimumDigits > totalDigits)
1653 totalDigits = minimumDigits;
1654 if (integerDigits > totalDigits)
1655 totalDigits = integerDigits;
1657 for (i = 0; i < totalDigits; ++i) {
1658 if (i == integerDigits) {
1659 // Record field information for caller.
1660 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1661 fieldPosition.setEndIndex(result.length());
1662 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
1663 fieldPosition.setEndIndex(result.length());
1666 // [Spark/CDL] Add attribute for integer part
1668 intEnd = result.length();
1669 addAttribute(Field.INTEGER, intBegin, result.length());
1671 result.append(decimal);
1672 // [Spark/CDL] Add attribute for decimal separator
1674 // Length of decimal separator is 1.
1675 int decimalSeparatorBegin = result.length() - 1;
1676 addAttribute(Field.DECIMAL_SEPARATOR, decimalSeparatorBegin,
1678 fracBegin = result.length();
1680 // Record field information for caller.
1681 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1682 fieldPosition.setBeginIndex(result.length());
1683 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
1684 fieldPosition.setBeginIndex(result.length());
1686 recordFractionDigits = fieldPosition instanceof UFieldPosition;
1689 byte digit = (i < digitList.count) ? digitList.getDigitValue(i) : (byte)0;
1690 result.append(digits[digit]);
1691 if (recordFractionDigits) {
1692 ++fractionalDigitsCount;
1693 fractionalDigits *= 10;
1694 fractionalDigits += digit;
1698 // For ICU compatibility and format 0 to 0E0 with pattern "#E0" [Richard/GCL]
1699 if (digitList.isZero() && (totalDigits == 0)) {
1700 result.append(digits[0]);
1703 // Record field information
1704 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) {
1705 if (fieldPosition.getEndIndex() < 0) {
1706 fieldPosition.setEndIndex(result.length());
1708 } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) {
1709 if (fieldPosition.getBeginIndex() < 0) {
1710 fieldPosition.setBeginIndex(result.length());
1712 fieldPosition.setEndIndex(result.length());
1713 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) {
1714 if (fieldPosition.getEndIndex() < 0) {
1715 fieldPosition.setEndIndex(result.length());
1717 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) {
1718 if (fieldPosition.getBeginIndex() < 0) {
1719 fieldPosition.setBeginIndex(result.length());
1721 fieldPosition.setEndIndex(result.length());
1723 if (recordFractionDigits) {
1724 ((UFieldPosition) fieldPosition).setFractionDigits(fractionalDigitsCount, fractionalDigits);
1727 // [Spark/CDL] Calcuate the end index of integer part and fractional
1728 // part if they are not properly processed yet.
1731 addAttribute(Field.INTEGER, intBegin, result.length());
1733 if (fracBegin > 0) {
1734 addAttribute(Field.FRACTION, fracBegin, result.length());
1738 // The exponent is output using the pattern-specified minimum exponent
1739 // digits. There is no maximum limit to the exponent digits, since truncating
1740 // the exponent would result in an unacceptable inaccuracy.
1741 result.append(symbols.getExponentSeparator());
1742 // [Spark/CDL] For exponent symbol, add an attribute.
1744 addAttribute(Field.EXPONENT_SYMBOL, result.length() -
1745 symbols.getExponentSeparator().length(), result.length());
1747 // For zero values, we force the exponent to zero. We must do this here, and
1748 // not earlier, because the value is used to determine integer digit count
1750 if (digitList.isZero())
1753 boolean negativeExponent = exponent < 0;
1754 if (negativeExponent) {
1755 exponent = -exponent;
1756 result.append(symbols.getMinusSign());
1757 // [Spark/CDL] If exponent has sign, then add an exponent sign
1760 // Length of exponent sign is 1.
1761 addAttribute(Field.EXPONENT_SIGN, result.length() - 1, result.length());
1763 } else if (exponentSignAlwaysShown) {
1764 result.append(symbols.getPlusSign());
1765 // [Spark/CDL] Add an plus sign attribute.
1767 // Length of exponent sign is 1.
1768 int expSignBegin = result.length() - 1;
1769 addAttribute(Field.EXPONENT_SIGN, expSignBegin, result.length());
1772 int expBegin = result.length();
1773 digitList.set(exponent);
1775 int expDig = minExponentDigits;
1776 if (useExponentialNotation && expDig < 1) {
1779 for (i = digitList.decimalAt; i < expDig; ++i)
1780 result.append(digits[0]);
1782 for (i = 0; i < digitList.decimalAt; ++i) {
1783 result.append((i < digitList.count) ? digits[digitList.getDigitValue(i)]
1786 // [Spark/CDL] Add attribute for exponent part.
1788 addAttribute(Field.EXPONENT, expBegin, result.length());
1792 private final void addPadding(StringBuffer result, FieldPosition fieldPosition, int prefixLen,
1794 if (formatWidth > 0) {
1795 int len = formatWidth - result.length();
1797 char[] padding = new char[len];
1798 for (int i = 0; i < len; ++i) {
1801 switch (padPosition) {
1802 case PAD_AFTER_PREFIX:
1803 result.insert(prefixLen, padding);
1805 case PAD_BEFORE_PREFIX:
1806 result.insert(0, padding);
1808 case PAD_BEFORE_SUFFIX:
1809 result.insert(result.length() - suffixLen, padding);
1811 case PAD_AFTER_SUFFIX:
1812 result.append(padding);
1815 if (padPosition == PAD_BEFORE_PREFIX || padPosition == PAD_AFTER_PREFIX) {
1816 fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + len);
1817 fieldPosition.setEndIndex(fieldPosition.getEndIndex() + len);
1824 * Parses the given string, returning a <code>Number</code> object to represent the
1825 * parsed value. <code>Double</code> objects are returned to represent non-integral
1826 * values which cannot be stored in a <code>BigDecimal</code>. These are
1827 * <code>NaN</code>, infinity, -infinity, and -0.0. If {@link #isParseBigDecimal()} is
1828 * false (the default), all other values are returned as <code>Long</code>,
1829 * <code>BigInteger</code>, or <code>BigDecimal</code> values, in that order of
1830 * preference. If {@link #isParseBigDecimal()} is true, all other values are returned
1831 * as <code>BigDecimal</code> valuse. If the parse fails, null is returned.
1833 * @param text the string to be parsed
1834 * @param parsePosition defines the position where parsing is to begin, and upon
1835 * return, the position where parsing left off. If the position has not changed upon
1836 * return, then parsing failed.
1837 * @return a <code>Number</code> object with the parsed value or
1838 * <code>null</code> if the parse failed
1842 public Number parse(String text, ParsePosition parsePosition) {
1843 return (Number) parse(text, parsePosition, null);
1847 * Parses text from the given string as a CurrencyAmount. Unlike the parse() method,
1848 * this method will attempt to parse a generic currency name, searching for a match of
1849 * this object's locale's currency display names, or for a 3-letter ISO currency
1850 * code. This method will fail if this format is not a currency format, that is, if it
1851 * does not contain the currency pattern symbol (U+00A4) in its prefix or suffix.
1853 * @param text the text to parse
1854 * @param pos input-output position; on input, the position within text to match; must
1855 * have 0 <= pos.getIndex() < text.length(); on output, the position after the last
1856 * matched character. If the parse fails, the position in unchanged upon output.
1857 * @return a CurrencyAmount, or null upon failure
1861 public CurrencyAmount parseCurrency(CharSequence text, ParsePosition pos) {
1862 Currency[] currency = new Currency[1];
1863 return (CurrencyAmount) parse(text.toString(), pos, currency);
1867 * Parses the given text as either a Number or a CurrencyAmount.
1869 * @param text the string to parse
1870 * @param parsePosition input-output position; on input, the position within text to
1871 * match; must have 0 <= pos.getIndex() < text.length(); on output, the position after
1872 * the last matched character. If the parse fails, the position in unchanged upon
1874 * @param currency if non-null, a CurrencyAmount is parsed and returned; otherwise a
1875 * Number is parsed and returned
1876 * @return a Number or CurrencyAmount or null
1878 private Object parse(String text, ParsePosition parsePosition, Currency[] currency) {
1880 int i = backup = parsePosition.getIndex();
1882 // Handle NaN as a special case:
1884 // Skip padding characters, if around prefix
1885 if (formatWidth > 0 &&
1886 (padPosition == PAD_BEFORE_PREFIX || padPosition == PAD_AFTER_PREFIX)) {
1887 i = skipPadding(text, i);
1889 if (text.regionMatches(i, symbols.getNaN(), 0, symbols.getNaN().length())) {
1890 i += symbols.getNaN().length();
1891 // Skip padding characters, if around suffix
1892 if (formatWidth > 0 && (padPosition == PAD_BEFORE_SUFFIX ||
1893 padPosition == PAD_AFTER_SUFFIX)) {
1894 i = skipPadding(text, i);
1896 parsePosition.setIndex(i);
1897 return new Double(Double.NaN);
1900 // NaN parse failed; start over
1903 boolean[] status = new boolean[STATUS_LENGTH];
1904 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) {
1905 if (!parseForCurrency(text, parsePosition, currency, status)) {
1909 if (!subparse(text, parsePosition, digitList, status, currency, negPrefixPattern,
1910 negSuffixPattern, posPrefixPattern, posSuffixPattern,
1911 false, Currency.SYMBOL_NAME)) {
1912 parsePosition.setIndex(backup);
1920 if (status[STATUS_INFINITE]) {
1921 n = new Double(status[STATUS_POSITIVE] ? Double.POSITIVE_INFINITY :
1922 Double.NEGATIVE_INFINITY);
1926 else if (status[STATUS_UNDERFLOW]) {
1927 n = status[STATUS_POSITIVE] ? new Double("0.0") : new Double("-0.0");
1931 else if (!status[STATUS_POSITIVE] && digitList.isZero()) {
1932 n = new Double("-0.0");
1936 // Do as much of the multiplier conversion as possible without
1938 int mult = multiplier; // Don't modify this.multiplier
1939 while (mult % 10 == 0) {
1940 --digitList.decimalAt;
1944 // Handle integral values
1945 if (!parseBigDecimal && mult == 1 && digitList.isIntegral()) {
1947 if (digitList.decimalAt < 12) { // quick check for long
1949 if (digitList.count > 0) {
1951 while (nx < digitList.count) {
1952 l = l * 10 + (char) digitList.digits[nx++] - '0';
1954 while (nx++ < digitList.decimalAt) {
1957 if (!status[STATUS_POSITIVE]) {
1961 n = Long.valueOf(l);
1963 BigInteger big = digitList.getBigInteger(status[STATUS_POSITIVE]);
1964 n = (big.bitLength() < 64) ? (Number) Long.valueOf(big.longValue()) : (Number) big;
1967 // Handle non-integral values or the case where parseBigDecimal is set
1969 BigDecimal big = digitList.getBigDecimalICU(status[STATUS_POSITIVE]);
1972 n = big.divide(BigDecimal.valueOf(mult), mathContext);
1977 // Assemble into CurrencyAmount if necessary
1978 return (currency != null) ? (Object) new CurrencyAmount(n, currency[0]) : (Object) n;
1981 private boolean parseForCurrency(String text, ParsePosition parsePosition,
1982 Currency[] currency, boolean[] status) {
1983 int origPos = parsePosition.getIndex();
1984 if (!isReadyForParsing) {
1985 int savedCurrencySignCount = currencySignCount;
1986 setupCurrencyAffixForAllPatterns();
1987 // reset pattern back
1988 if (savedCurrencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
1989 applyPatternWithoutExpandAffix(formatPattern, false);
1991 applyPattern(formatPattern, false);
1993 isReadyForParsing = true;
1995 int maxPosIndex = origPos;
1996 int maxErrorPos = -1;
1997 boolean[] savedStatus = null;
1998 // First, parse against current pattern.
1999 // Since current pattern could be set by applyPattern(),
2000 // it could be an arbitrary pattern, and it may not be the one
2001 // defined in current locale.
2002 boolean[] tmpStatus = new boolean[STATUS_LENGTH];
2003 ParsePosition tmpPos = new ParsePosition(origPos);
2004 DigitList tmpDigitList = new DigitList();
2006 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
2007 found = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency,
2008 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern,
2009 true, Currency.LONG_NAME);
2011 found = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency,
2012 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern,
2013 true, Currency.SYMBOL_NAME);
2016 if (tmpPos.getIndex() > maxPosIndex) {
2017 maxPosIndex = tmpPos.getIndex();
2018 savedStatus = tmpStatus;
2019 digitList = tmpDigitList;
2022 maxErrorPos = tmpPos.getErrorIndex();
2024 // Then, parse against affix patterns. Those are currency patterns and currency
2025 // plural patterns defined in the locale.
2026 for (AffixForCurrency affix : affixPatternsForCurrency) {
2027 tmpStatus = new boolean[STATUS_LENGTH];
2028 tmpPos = new ParsePosition(origPos);
2029 tmpDigitList = new DigitList();
2030 boolean result = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency,
2031 affix.getNegPrefix(), affix.getNegSuffix(),
2032 affix.getPosPrefix(), affix.getPosSuffix(),
2033 true, affix.getPatternType());
2036 if (tmpPos.getIndex() > maxPosIndex) {
2037 maxPosIndex = tmpPos.getIndex();
2038 savedStatus = tmpStatus;
2039 digitList = tmpDigitList;
2042 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? tmpPos.getErrorIndex()
2046 // Finally, parse against simple affix to find the match. For example, in
2047 // TestMonster suite, if the to-be-parsed text is "-\u00A40,00".
2048 // complexAffixCompare will not find match, since there is no ISO code matches
2049 // "\u00A4", and the parse stops at "\u00A4". We will just use simple affix
2050 // comparison (look for exact match) to pass it.
2052 // TODO: We should parse against simple affix first when
2053 // output currency is not requested. After the complex currency
2054 // parsing implementation was introduced, the default currency
2055 // instance parsing slowed down because of the new code flow.
2056 // I filed #10312 - Yoshito
2057 tmpStatus = new boolean[STATUS_LENGTH];
2058 tmpPos = new ParsePosition(origPos);
2059 tmpDigitList = new DigitList();
2061 // Disable complex currency parsing and try it again.
2062 boolean result = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency,
2063 negativePrefix, negativeSuffix, positivePrefix, positiveSuffix,
2064 false /* disable complex currency parsing */, Currency.SYMBOL_NAME);
2066 if (tmpPos.getIndex() > maxPosIndex) {
2067 maxPosIndex = tmpPos.getIndex();
2068 savedStatus = tmpStatus;
2069 digitList = tmpDigitList;
2073 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? tmpPos.getErrorIndex() :
2078 // parsePosition.setIndex(origPos);
2079 parsePosition.setErrorIndex(maxErrorPos);
2081 parsePosition.setIndex(maxPosIndex);
2082 parsePosition.setErrorIndex(-1);
2083 for (int index = 0; index < STATUS_LENGTH; ++index) {
2084 status[index] = savedStatus[index];
2090 // Get affix patterns used in locale's currency pattern (NumberPatterns[1]) and
2091 // currency plural pattern (CurrencyUnitPatterns).
2092 private void setupCurrencyAffixForAllPatterns() {
2093 if (currencyPluralInfo == null) {
2094 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale());
2096 affixPatternsForCurrency = new HashSet<AffixForCurrency>();
2098 // save the current pattern, since it will be changed by
2099 // applyPatternWithoutExpandAffix
2100 String savedFormatPattern = formatPattern;
2102 // CURRENCYSTYLE and ISOCURRENCYSTYLE should have the same prefix and suffix, so,
2103 // only need to save one of them. Here, chose onlyApplyPatternWithoutExpandAffix
2104 // without saving the actualy pattern in 'pattern' data member. TODO: is it uloc?
2105 applyPatternWithoutExpandAffix(getPattern(symbols.getULocale(), NumberFormat.CURRENCYSTYLE),
2107 AffixForCurrency affixes = new AffixForCurrency(
2108 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern,
2109 Currency.SYMBOL_NAME);
2110 affixPatternsForCurrency.add(affixes);
2112 // add plural pattern
2113 Iterator<String> iter = currencyPluralInfo.pluralPatternIterator();
2114 Set<String> currencyUnitPatternSet = new HashSet<String>();
2115 while (iter.hasNext()) {
2116 String pluralCount = iter.next();
2117 String currencyPattern = currencyPluralInfo.getCurrencyPluralPattern(pluralCount);
2118 if (currencyPattern != null &&
2119 currencyUnitPatternSet.contains(currencyPattern) == false) {
2120 currencyUnitPatternSet.add(currencyPattern);
2121 applyPatternWithoutExpandAffix(currencyPattern, false);
2122 affixes = new AffixForCurrency(negPrefixPattern, negSuffixPattern, posPrefixPattern,
2123 posSuffixPattern, Currency.LONG_NAME);
2124 affixPatternsForCurrency.add(affixes);
2127 // reset pattern back
2128 formatPattern = savedFormatPattern;
2131 // currency formatting style options
2132 private static final int CURRENCY_SIGN_COUNT_ZERO = 0;
2133 private static final int CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT = 1;
2134 private static final int CURRENCY_SIGN_COUNT_IN_ISO_FORMAT = 2;
2135 private static final int CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT = 3;
2137 private static final int STATUS_INFINITE = 0;
2138 private static final int STATUS_POSITIVE = 1;
2139 private static final int STATUS_UNDERFLOW = 2;
2140 private static final int STATUS_LENGTH = 3;
2142 private static final UnicodeSet dotEquivalents = new UnicodeSet(
2143 //"[.\u2024\u3002\uFE12\uFE52\uFF0E\uFF61]"
2150 0xFF61, 0xFF61).freeze();
2152 private static final UnicodeSet commaEquivalents = new UnicodeSet(
2153 //"[,\u060C\u066B\u3001\uFE10\uFE11\uFE50\uFE51\uFF0C\uFF64]"
2161 0xFF64, 0xFF64).freeze();
2163 // private static final UnicodeSet otherGroupingSeparators = new UnicodeSet(
2164 // //"[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]"
2174 // 0xFF07, 0xFF07).freeze();
2176 private static final UnicodeSet strictDotEquivalents = new UnicodeSet(
2177 //"[.\u2024\uFE52\uFF0E\uFF61]"
2182 0xFF61, 0xFF61).freeze();
2184 private static final UnicodeSet strictCommaEquivalents = new UnicodeSet(
2185 //"[,\u066B\uFE10\uFE50\uFF0C]"
2190 0xFF0C, 0xFF0C).freeze();
2192 // private static final UnicodeSet strictOtherGroupingSeparators = new UnicodeSet(
2193 // //"[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]"
2203 // 0xFF07, 0xFF07).freeze();
2205 private static final UnicodeSet defaultGroupingSeparators =
2206 // new UnicodeSet(dotEquivalents).addAll(commaEquivalents)
2207 // .addAll(otherGroupingSeparators).freeze();
2228 0xFF64, 0xFF64).freeze();
2230 private static final UnicodeSet strictDefaultGroupingSeparators =
2231 // new UnicodeSet(strictDotEquivalents).addAll(strictCommaEquivalents)
2232 // .addAll(strictOtherGroupingSeparators).freeze();
2252 0xFF61, 0xFF61).freeze();
2254 private static final UnicodeSet minusSigns =
2262 0xFF0D, 0xFF0D).freeze();
2264 private static final UnicodeSet plusSigns =
2272 0xFF0B, 0xFF0B).freeze();
2275 // When parsing a number with big exponential value, it requires to transform the
2276 // value into a string representation to construct BigInteger instance. We want to
2277 // set the maximum size because it can easily trigger OutOfMemoryException.
2278 // PARSE_MAX_EXPONENT is currently set to 1000 (See getParseMaxDigits()),
2279 // which is much bigger than MAX_VALUE of Double ( See the problem reported by ticket#5698
2280 private int PARSE_MAX_EXPONENT = 1000;
2283 * Parses the given text into a number. The text is parsed beginning at parsePosition,
2284 * until an unparseable character is seen.
2286 * @param text the string to parse.
2287 * @param parsePosition the position at which to being parsing. Upon return, the first
2288 * unparseable character.
2289 * @param digits the DigitList to set to the parsed value.
2290 * @param status Upon return contains boolean status flags indicating whether the
2291 * value was infinite and whether it was positive.
2292 * @param currency return value for parsed currency, for generic currency parsing
2293 * mode, or null for normal parsing. In generic currency parsing mode, any currency is
2294 * parsed, not just the currency that this formatter is set to.
2295 * @param negPrefix negative prefix pattern
2296 * @param negSuffix negative suffix pattern
2297 * @param posPrefix positive prefix pattern
2298 * @param negSuffix negative suffix pattern
2299 * @param complexCurrencyParsing whether it is complex currency parsing or not.
2300 * @param type type of currency to parse against, LONG_NAME only or not.
2302 private final boolean subparse(
2303 String text, ParsePosition parsePosition, DigitList digits,
2304 boolean status[], Currency currency[], String negPrefix, String negSuffix, String posPrefix,
2305 String posSuffix, boolean parseComplexCurrency, int type) {
2307 int position = parsePosition.getIndex();
2308 int oldStart = parsePosition.getIndex();
2310 // Match padding before prefix
2311 if (formatWidth > 0 && padPosition == PAD_BEFORE_PREFIX) {
2312 position = skipPadding(text, position);
2315 // Match positive and negative prefixes; prefer longest match.
2316 int posMatch = compareAffix(text, position, false, true, posPrefix, parseComplexCurrency, type, currency);
2317 int negMatch = compareAffix(text, position, true, true, negPrefix, parseComplexCurrency, type, currency);
2318 if (posMatch >= 0 && negMatch >= 0) {
2319 if (posMatch > negMatch) {
2321 } else if (negMatch > posMatch) {
2325 if (posMatch >= 0) {
2326 position += posMatch;
2327 } else if (negMatch >= 0) {
2328 position += negMatch;
2330 parsePosition.setErrorIndex(position);
2334 // Match padding after prefix
2335 if (formatWidth > 0 && padPosition == PAD_AFTER_PREFIX) {
2336 position = skipPadding(text, position);
2339 // process digits or Inf, find decimal position
2340 status[STATUS_INFINITE] = false;
2341 if (text.regionMatches(position, symbols.getInfinity(), 0,
2342 symbols.getInfinity().length())) {
2343 position += symbols.getInfinity().length();
2344 status[STATUS_INFINITE] = true;
2346 // We now have a string of digits, possibly with grouping symbols, and decimal
2347 // points. We want to process these into a DigitList. We don't want to put a
2348 // bunch of leading zeros into the DigitList though, so we keep track of the
2349 // location of the decimal point, put only significant digits into the
2350 // DigitList, and adjust the exponent as needed.
2352 digits.decimalAt = digits.count = 0;
2353 char [] digitSymbols = symbols.getDigitsLocal();
2354 char decimal = (currencySignCount == CURRENCY_SIGN_COUNT_ZERO) ?
2355 symbols.getDecimalSeparator() : symbols.getMonetaryDecimalSeparator();
2356 char grouping = (currencySignCount == CURRENCY_SIGN_COUNT_ZERO) ?
2357 symbols.getGroupingSeparator() : symbols.getMonetaryGroupingSeparator();
2359 String exponentSep = symbols.getExponentSeparator();
2360 boolean sawDecimal = false;
2361 boolean sawGrouping = false;
2362 boolean sawExponent = false;
2363 boolean sawDigit = false;
2364 long exponent = 0; // Set to the exponent value, if any
2368 boolean strictParse = isParseStrict();
2369 boolean strictFail = false; // did we exit with a strict parse failure?
2370 int lastGroup = -1; // where did we last see a grouping separator?
2371 int digitStart = position; // where did the digit start?
2372 int gs2 = groupingSize2 == 0 ? groupingSize : groupingSize2;
2374 // equivalent grouping and decimal support
2375 boolean skipExtendedSeparatorParsing = ICUConfig.get(
2376 "com.ibm.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false")
2379 UnicodeSet decimalEquiv = skipExtendedSeparatorParsing ? UnicodeSet.EMPTY :
2380 getEquivalentDecimals(decimal, strictParse);
2381 UnicodeSet groupEquiv = skipExtendedSeparatorParsing ? UnicodeSet.EMPTY :
2382 (strictParse ? strictDefaultGroupingSeparators : defaultGroupingSeparators);
2384 // We have to track digitCount ourselves, because digits.count will pin when
2385 // the maximum allowable digits is reached.
2390 for (; position < text.length(); position += UTF16.getCharCount(ch)) {
2391 ch = UTF16.charAt(text,position);
2394 // We recognize all digit ranges, not only the Latin digit range
2395 // '0'..'9'. We do so by using the UCharacter.digit() method, which
2396 // converts a valid Unicode digit to the range 0..9.
2398 // The character 'ch' may be a digit. If so, place its value from 0 to 9
2399 // in 'digit'. First try using the locale digit, which may or MAY NOT be a
2400 // standard Unicode digit range. If this fails, try using the standard
2401 // Unicode digit ranges by calling UCharacter.digit(). If this also fails,
2402 // digit will have a value outside the range 0..9.
2403 digit = ch - digitSymbols[0];
2404 if (digit < 0 || digit > 9)
2405 digit = UCharacter.digit(ch, 10);
2406 if (digit < 0 || digit > 9) {
2407 for ( digit = 0 ; digit < 10 ; digit++) {
2408 if ( ch == digitSymbols[digit] )
2416 // Cancel out backup setting (see grouping handler below)
2417 if (strictParse && backup != -1) {
2418 // comma followed by digit, so group before comma is a secondary
2419 // group. If there was a group separator before that, the group
2420 // must == the secondary group length, else it can be <= the the
2421 // secondary group length.
2422 if ((lastGroup != -1 && countCodePoints(text, lastGroup, backup) - 1 != gs2)
2423 || (lastGroup == -1 && countCodePoints(text, digitStart, position) - 1 > gs2)) {
2429 backup = -1; // Do this BEFORE continue statement below!!!
2432 // Handle leading zeros
2433 if (digits.count == 0) {
2435 // Ignore leading zeros in integer part of number.
2439 // If we have seen the decimal, but no significant digits yet,
2440 // then we account for leading zeros by decrementing the
2441 // digits.decimalAt into negative values.
2445 digits.append((char) (digit + '0'));
2447 } else if (digit > 0 && digit <= 9) // [sic] digit==0 handled above
2451 if ((lastGroup != -1 && countCodePoints(text, lastGroup, backup) - 1 != gs2)
2452 || (lastGroup == -1 && countCodePoints(text, digitStart, position) - 1 > gs2)) {
2462 digits.append((char) (digit + '0'));
2464 // Cancel out backup setting (see grouping handler below)
2466 } else if (ch == decimal) {
2469 (lastGroup != -1 && countCodePoints(text,lastGroup,position) != groupingSize + 1)) {
2474 // If we're only parsing integers, or if we ALREADY saw the decimal,
2475 // then don't parse this one.
2476 if (isParseIntegerOnly() || sawDecimal) {
2479 digits.decimalAt = digitCount; // Not digits.count!
2481 } else if (isGroupingUsed() && ch == grouping) {
2486 if ((!sawDigit || backup != -1)) {
2487 // leading group, or two group separators in a row
2492 // Ignore grouping characters, if we are using them, but require that
2493 // they be followed by a digit. Otherwise we backup and reprocess
2497 } else if (!sawDecimal && decimalEquiv.contains(ch)) {
2500 (lastGroup != -1 && countCodePoints(text,lastGroup,position) != groupingSize + 1)) {
2505 // If we're only parsing integers, then don't parse this one.
2506 if (isParseIntegerOnly())
2508 digits.decimalAt = digitCount; // Not digits.count!
2510 // Once we see a decimal separator character, we only accept that
2511 // decimal separator character from then on.
2512 decimal = (char) ch;
2514 } else if (isGroupingUsed() && !sawGrouping && groupEquiv.contains(ch)) {
2519 if ((!sawDigit || backup != -1)) {
2520 // leading group, or two group separators in a row
2525 // Once we see a grouping character, we only accept that grouping
2526 // character from then on.
2527 grouping = (char) ch;
2529 // Ignore grouping characters, if we are using them, but require that
2530 // they be followed by a digit. Otherwise we backup and reprocess
2534 } else if (!sawExponent && text.regionMatches(true, position, exponentSep, 0, exponentSep.length())) {
2535 // Parse sign, if present
2536 boolean negExp = false;
2537 int pos = position + exponentSep.length();
2538 if (pos < text.length()) {
2539 ch = UTF16.charAt(text,pos);
2540 if (ch == symbols.getPlusSign()) {
2542 } else if (ch == symbols.getMinusSign()) {
2548 DigitList exponentDigits = new DigitList();
2549 exponentDigits.count = 0;
2550 while (pos < text.length()) {
2551 digit = UTF16.charAt(text,pos) - digitSymbols[0];
2552 if (digit < 0 || digit > 9) {
2553 // Can't parse "[1E0]" when pattern is "0.###E0;[0.###E0]"
2554 // Should update reassign the value of 'ch' in the code: digit
2555 // = Character.digit(ch, 10); [Richard/GCL]
2556 digit = UCharacter.digit(UTF16.charAt(text,pos), 10);
2558 if (digit >= 0 && digit <= 9) {
2559 exponentDigits.append((char) (digit + '0'));
2560 pos += UTF16.getCharCount(UTF16.charAt(text,pos));
2566 if (exponentDigits.count > 0) {
2567 // defer strict parse until we know we have a bona-fide exponent
2569 if (backup != -1 || lastGroup != -1) {
2575 // Quick overflow check for exponential part. Actual limit check
2576 // will be done later in this code.
2577 if (exponentDigits.count > 10 /* maximum decimal digits for int */) {
2579 // set underflow flag
2580 status[STATUS_UNDERFLOW] = true;
2582 // set infinite flag
2583 status[STATUS_INFINITE] = true;
2586 exponentDigits.decimalAt = exponentDigits.count;
2587 exponent = exponentDigits.getLong();
2589 exponent = -exponent;
2592 position = pos; // Advance past the exponent
2596 break; // Whether we fail or succeed, we exit this loop
2605 // If there was no decimal point we have an integer
2607 digits.decimalAt = digitCount; // Not digits.count!
2609 // check for strict parse errors
2610 if (strictParse && !sawDecimal) {
2611 if (lastGroup != -1 && countCodePoints(text,lastGroup,position) != groupingSize + 1) {
2616 // only set with strictParse and a leading zero error leading zeros are an
2617 // error with strict parsing except immediately before nondigit (except
2618 // group separator followed by digit), or end of text.
2620 parsePosition.setIndex(oldStart);
2621 parsePosition.setErrorIndex(position);
2625 // Adjust for exponent, if any
2626 exponent += digits.decimalAt;
2627 if (exponent < -getParseMaxDigits()) {
2628 status[STATUS_UNDERFLOW] = true;
2629 } else if (exponent > getParseMaxDigits()) {
2630 status[STATUS_INFINITE] = true;
2632 digits.decimalAt = (int) exponent;
2635 // If none of the text string was recognized. For example, parse "x" with
2636 // pattern "#0.00" (return index and error index both 0) parse "$" with
2637 // pattern "$#0.00". (return index 0 and error index 1).
2638 if (!sawDigit && digitCount == 0) {
2639 parsePosition.setIndex(oldStart);
2640 parsePosition.setErrorIndex(oldStart);
2645 // Match padding before suffix
2646 if (formatWidth > 0 && padPosition == PAD_BEFORE_SUFFIX) {
2647 position = skipPadding(text, position);
2650 // Match positive and negative suffixes; prefer longest match.
2651 if (posMatch >= 0) {
2652 posMatch = compareAffix(text, position, false, false, posSuffix, parseComplexCurrency, type, currency);
2654 if (negMatch >= 0) {
2655 negMatch = compareAffix(text, position, true, false, negSuffix, parseComplexCurrency, type, currency);
2657 if (posMatch >= 0 && negMatch >= 0) {
2658 if (posMatch > negMatch) {
2660 } else if (negMatch > posMatch) {
2665 // Fail if neither or both
2666 if ((posMatch >= 0) == (negMatch >= 0)) {
2667 parsePosition.setErrorIndex(position);
2671 position += (posMatch >= 0 ? posMatch : negMatch);
2673 // Match padding after suffix
2674 if (formatWidth > 0 && padPosition == PAD_AFTER_SUFFIX) {
2675 position = skipPadding(text, position);
2678 parsePosition.setIndex(position);
2680 status[STATUS_POSITIVE] = (posMatch >= 0);
2682 if (parsePosition.getIndex() == oldStart) {
2683 parsePosition.setErrorIndex(position);
2689 // Utility method used to count the number of codepoints
2690 private int countCodePoints(String str,int start, int end) {
2693 while ( index < end ) {
2695 index += UTF16.getCharCount(UTF16.charAt(str, index));
2700 * Returns a set of characters equivalent to the given desimal separator used for
2701 * parsing number. This method may return an empty set.
2703 private UnicodeSet getEquivalentDecimals(char decimal, boolean strictParse) {
2704 UnicodeSet equivSet = UnicodeSet.EMPTY;
2706 if (strictDotEquivalents.contains(decimal)) {
2707 equivSet = strictDotEquivalents;
2708 } else if (strictCommaEquivalents.contains(decimal)) {
2709 equivSet = strictCommaEquivalents;
2712 if (dotEquivalents.contains(decimal)) {
2713 equivSet = dotEquivalents;
2714 } else if (commaEquivalents.contains(decimal)) {
2715 equivSet = commaEquivalents;
2722 * Starting at position, advance past a run of pad characters, if any. Return the
2723 * index of the first character after position that is not a pad character. Result is
2726 private final int skipPadding(String text, int position) {
2727 while (position < text.length() && text.charAt(position) == pad) {
2734 * Returns the length matched by the given affix, or -1 if none. Runs of white space
2735 * in the affix, match runs of white space in the input. Pattern white space and input
2736 * white space are determined differently; see code.
2738 * @param text input text
2739 * @param pos offset into input at which to begin matching
2742 * @param affixPat affix pattern used for currency affix comparison
2743 * @param copmplexCurrencyParsing whether it is currency parsing or not
2744 * @param type compare against currency type, LONG_NAME only or not.
2745 * @param currency return value for parsed currency, for generic currency parsing
2746 * mode, or null for normal parsing. In generic currency parsing mode, any currency
2747 * is parsed, not just the currency that this formatter is set to.
2748 * @return length of input that matches, or -1 if match failure
2750 private int compareAffix(String text, int pos, boolean isNegative, boolean isPrefix,
2751 String affixPat, boolean complexCurrencyParsing, int type, Currency[] currency) {
2752 if (currency != null || currencyChoice != null || (currencySignCount != CURRENCY_SIGN_COUNT_ZERO && complexCurrencyParsing)) {
2753 return compareComplexAffix(affixPat, text, pos, type, currency);
2756 return compareSimpleAffix(isNegative ? negativePrefix : positivePrefix, text, pos);
2758 return compareSimpleAffix(isNegative ? negativeSuffix : positiveSuffix, text, pos);
2764 * Check for bidi marks: LRM, RLM, ALM
2766 private static boolean isBidiMark(int c) {
2767 return (c==0x200E || c==0x200F || c==0x061C);
2771 * Remove bidi marks from affix
2773 private static final int TRIM_BUFLEN = 32;
2774 private static String trimMarksFromAffix(String affix) {
2775 boolean hasBidiMark = false;
2777 for (; idx < affix.length(); idx++) {
2778 if (isBidiMark(affix.charAt(idx))) {
2787 StringBuilder buf = new StringBuilder();
2788 buf.append(affix, 0, idx);
2789 idx++; // skip the first Bidi mark
2790 for (; idx < affix.length(); idx++) {
2791 char c = affix.charAt(idx);
2792 if (!isBidiMark(c)) {
2797 return buf.toString();
2801 * Return the length matched by the given affix, or -1 if none. Runs of white space in
2802 * the affix, match runs of white space in the input. Pattern white space and input
2803 * white space are determined differently; see code.
2805 * @param affix pattern string, taken as a literal
2806 * @param input input text
2807 * @param pos offset into input at which to begin matching
2808 * @return length of input that matches, or -1 if match failure
2810 private static int compareSimpleAffix(String affix, String input, int pos) {
2812 // Affixes here might consist of sign, currency symbol and related spacing, etc.
2813 // For more efficiency we should keep lazily-created trimmed affixes around in
2814 // instance variables instead of trimming each time they are used (the next step).
2815 String trimmedAffix = (affix.length() > 1)? trimMarksFromAffix(affix): affix;
2816 for (int i = 0; i < trimmedAffix.length();) {
2817 int c = UTF16.charAt(trimmedAffix, i);
2818 int len = UTF16.getCharCount(c);
2819 if (PatternProps.isWhiteSpace(c)) {
2820 // We may have a pattern like: \u200F and input text like: \u200F Note
2821 // that U+200F and U+0020 are Pattern_White_Space but only U+0020 is
2822 // UWhiteSpace. So we have to first do a direct match of the run of RULE
2823 // whitespace in the pattern, then match any extra characters.
2824 boolean literalMatch = false;
2825 while (pos < input.length()) {
2826 int ic = UTF16.charAt(input, pos);
2828 literalMatch = true;
2831 if (i == trimmedAffix.length()) {
2834 c = UTF16.charAt(trimmedAffix, i);
2835 len = UTF16.getCharCount(c);
2836 if (!PatternProps.isWhiteSpace(c)) {
2839 } else if (isBidiMark(ic)) {
2840 pos++; // just skip over this input text
2846 // Advance over run in trimmedAffix
2847 i = skipPatternWhiteSpace(trimmedAffix, i);
2849 // Advance over run in input text. Must see at least one white space char
2850 // in input, unless we've already matched some characters literally.
2852 pos = skipUWhiteSpace(input, pos);
2853 if (pos == s && !literalMatch) {
2856 // If we skip UWhiteSpace in the input text, we need to skip it in the
2857 // pattern. Otherwise, the previous lines may have skipped over text
2858 // (such as U+00A0) that is also in the trimmedAffix.
2859 i = skipUWhiteSpace(trimmedAffix, i);
2861 boolean match = false;
2862 while (pos < input.length()) {
2863 int ic = UTF16.charAt(input, pos);
2864 if (!match && equalWithSignCompatibility(ic, c)) {
2868 } else if (isBidiMark(ic)) {
2869 pos++; // just skip over this input text
2882 private static boolean equalWithSignCompatibility(int lhs, int rhs) {
2884 || (minusSigns.contains(lhs) && minusSigns.contains(rhs))
2885 || (plusSigns.contains(lhs) && plusSigns.contains(rhs));
2889 * Skips over a run of zero or more Pattern_White_Space characters at pos in text.
2891 private static int skipPatternWhiteSpace(String text, int pos) {
2892 while (pos < text.length()) {
2893 int c = UTF16.charAt(text, pos);
2894 if (!PatternProps.isWhiteSpace(c)) {
2897 pos += UTF16.getCharCount(c);
2903 * Skips over a run of zero or more isUWhiteSpace() characters at pos in text.
2905 private static int skipUWhiteSpace(String text, int pos) {
2906 while (pos < text.length()) {
2907 int c = UTF16.charAt(text, pos);
2908 if (!UCharacter.isUWhiteSpace(c)) {
2911 pos += UTF16.getCharCount(c);
2917 * Skips over a run of zero or more bidi marks at pos in text.
2919 private static int skipBidiMarks(String text, int pos) {
2920 while (pos < text.length()) {
2921 int c = UTF16.charAt(text, pos);
2922 if (!isBidiMark(c)) {
2925 pos += UTF16.getCharCount(c);
2931 * Returns the length matched by the given affix, or -1 if none.
2933 * @param affixPat pattern string
2934 * @param text input text
2935 * @param pos offset into input at which to begin matching
2936 * @param type parse against currency type, LONG_NAME only or not.
2937 * @param currency return value for parsed currency, for generic
2938 * currency parsing mode, or null for normal parsing. In generic
2939 * currency parsing mode, any currency is parsed, not just the
2940 * currency that this formatter is set to.
2941 * @return position after the matched text, or -1 if match failure
2943 private int compareComplexAffix(String affixPat, String text, int pos, int type,
2944 Currency[] currency) {
2946 for (int i = 0; i < affixPat.length() && pos >= 0;) {
2947 char c = affixPat.charAt(i++);
2950 int j = affixPat.indexOf(QUOTE, i);
2952 pos = match(text, pos, QUOTE);
2956 pos = match(text, pos, affixPat.substring(i, j));
2958 if (i < affixPat.length() && affixPat.charAt(i) == QUOTE) {
2959 pos = match(text, pos, QUOTE);
2966 // Unterminated quote; should be caught by apply
2968 throw new RuntimeException();
2976 // since the currency names in choice format is saved the same way as
2977 // other currency names, do not need to do currency choice parsing here.
2978 // the general currency parsing parse against all names, including names
2979 // in choice format. assert(currency != null || (getCurrency() != null &&
2980 // currencyChoice != null));
2981 boolean intl = i < affixPat.length() && affixPat.charAt(i) == CURRENCY_SIGN;
2985 boolean plural = i < affixPat.length() && affixPat.charAt(i) == CURRENCY_SIGN;
2990 // Parse generic currency -- anything for which we have a display name, or
2991 // any 3-letter ISO code. Try to parse display name for our locale; first
2992 // determine our locale. TODO: use locale in CurrencyPluralInfo
2993 ULocale uloc = getLocale(ULocale.VALID_LOCALE);
2995 // applyPattern has been called; use the symbols
2996 uloc = symbols.getLocale(ULocale.VALID_LOCALE);
2998 // Delegate parse of display name => ISO code to Currency
2999 ParsePosition ppos = new ParsePosition(pos);
3000 // using Currency.parse to handle mixed style parsing.
3001 String iso = Currency.parse(uloc, text, type, ppos);
3003 // If parse succeeds, populate currency[0]
3005 if (currency != null) {
3006 currency[0] = Currency.getInstance(iso);
3008 // The formatter is currency-style but the client has not requested
3009 // the value of the parsed currency. In this case, if that value does
3010 // not match the formatter's current value, then the parse fails.
3011 Currency effectiveCurr = getEffectiveCurrency();
3012 if (iso.compareTo(effectiveCurr.getCurrencyCode()) != 0) {
3017 pos = ppos.getIndex();
3022 case PATTERN_PERCENT:
3023 c = symbols.getPercent();
3025 case PATTERN_PER_MILLE:
3026 c = symbols.getPerMill();
3029 c = symbols.getMinusSign();
3032 pos = match(text, pos, c);
3033 if (PatternProps.isWhiteSpace(c)) {
3034 i = skipPatternWhiteSpace(affixPat, i);
3042 * Matches a single character at text[pos] and return the index of the next character
3043 * upon success. Return -1 on failure. If ch is a Pattern_White_Space then match a run of
3044 * white space in text.
3046 static final int match(String text, int pos, int ch) {
3047 if (pos < 0 || pos >= text.length()) {
3050 pos = skipBidiMarks(text, pos);
3051 if (PatternProps.isWhiteSpace(ch)) {
3052 // Advance over run of white space in input text
3053 // Must see at least one white space char in input
3055 pos = skipPatternWhiteSpace(text, pos);
3061 if (pos >= text.length() || UTF16.charAt(text, pos) != ch) {
3064 pos = skipBidiMarks(text, pos + UTF16.getCharCount(ch));
3069 * Matches a string at text[pos] and return the index of the next character upon
3070 * success. Return -1 on failure. Match a run of white space in str with a run of
3071 * white space in text.
3073 static final int match(String text, int pos, String str) {
3074 for (int i = 0; i < str.length() && pos >= 0;) {
3075 int ch = UTF16.charAt(str, i);
3076 i += UTF16.getCharCount(ch);
3077 pos = match(text, pos, ch);
3078 if (PatternProps.isWhiteSpace(ch)) {
3079 i = skipPatternWhiteSpace(str, i);
3086 * Returns a copy of the decimal format symbols used by this format.
3088 * @return desired DecimalFormatSymbols
3089 * @see DecimalFormatSymbols
3092 public DecimalFormatSymbols getDecimalFormatSymbols() {
3094 // don't allow multiple references
3095 return (DecimalFormatSymbols) symbols.clone();
3096 } catch (Exception foo) {
3097 return null; // should never happen
3102 * Sets the decimal format symbols used by this format. The format uses a copy of the
3105 * @param newSymbols desired DecimalFormatSymbols
3106 * @see DecimalFormatSymbols
3109 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
3110 symbols = (DecimalFormatSymbols) newSymbols.clone();
3111 setCurrencyForSymbols();
3112 expandAffixes(null);
3116 * Update the currency object to match the symbols. This method is used only when the
3117 * caller has passed in a symbols object that may not be the default object for its
3120 private void setCurrencyForSymbols() {
3122 // Bug 4212072 Update the affix strings according to symbols in order to keep the
3123 // affix strings up to date. [Richard/GCL]
3125 // With the introduction of the Currency object, the currency symbols in the DFS
3126 // object are ignored. For backward compatibility, we check any explicitly set DFS
3127 // object. If it is a default symbols object for its locale, we change the
3128 // currency object to one for that locale. If it is custom, we set the currency to
3130 DecimalFormatSymbols def = new DecimalFormatSymbols(symbols.getULocale());
3132 if (symbols.getCurrencySymbol().equals(def.getCurrencySymbol())
3133 && symbols.getInternationalCurrencySymbol()
3134 .equals(def.getInternationalCurrencySymbol())) {
3135 setCurrency(Currency.getInstance(symbols.getULocale()));
3142 * Returns the positive prefix.
3144 * <p>Examples: +123, $123, sFr123
3145 * @return the prefix
3148 public String getPositivePrefix() {
3149 return positivePrefix;
3153 * Sets the positive prefix.
3155 * <p>Examples: +123, $123, sFr123
3156 * @param newValue the prefix
3159 public void setPositivePrefix(String newValue) {
3160 positivePrefix = newValue;
3161 posPrefixPattern = null;
3165 * Returns the negative prefix.
3167 * <p>Examples: -123, ($123) (with negative suffix), sFr-123
3169 * @return the prefix
3172 public String getNegativePrefix() {
3173 return negativePrefix;
3177 * Sets the negative prefix.
3179 * <p>Examples: -123, ($123) (with negative suffix), sFr-123
3180 * @param newValue the prefix
3183 public void setNegativePrefix(String newValue) {
3184 negativePrefix = newValue;
3185 negPrefixPattern = null;
3189 * Returns the positive suffix.
3193 * @return the suffix
3196 public String getPositiveSuffix() {
3197 return positiveSuffix;
3201 * Sets the positive suffix.
3204 * @param newValue the suffix
3207 public void setPositiveSuffix(String newValue) {
3208 positiveSuffix = newValue;
3209 posSuffixPattern = null;
3213 * Returns the negative suffix.
3215 * <p>Examples: -123%, ($123) (with positive suffixes)
3217 * @return the suffix
3220 public String getNegativeSuffix() {
3221 return negativeSuffix;
3225 * Sets the positive suffix.
3228 * @param newValue the suffix
3231 public void setNegativeSuffix(String newValue) {
3232 negativeSuffix = newValue;
3233 negSuffixPattern = null;
3237 * Returns the multiplier for use in percent, permill, etc. For a percentage, set the
3238 * suffixes to have "%" and the multiplier to be 100. (For Arabic, use arabic percent
3239 * symbol). For a permill, set the suffixes to have "\u2031" and the multiplier to be
3242 * <p>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
3244 * @return the multiplier
3247 public int getMultiplier() {
3252 * Sets the multiplier for use in percent, permill, etc. For a percentage, set the
3253 * suffixes to have "%" and the multiplier to be 100. (For Arabic, use arabic percent
3254 * symbol). For a permill, set the suffixes to have "\u2031" and the multiplier to be
3257 * <p>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
3259 * @param newValue the multiplier
3262 public void setMultiplier(int newValue) {
3263 if (newValue == 0) {
3264 throw new IllegalArgumentException("Bad multiplier: " + newValue);
3266 multiplier = newValue;
3270 * {@icu} Returns the rounding increment.
3272 * @return A positive rounding increment, or <code>null</code> if a custom rounding
3273 * increment is not in effect.
3274 * @see #setRoundingIncrement
3275 * @see #getRoundingMode
3276 * @see #setRoundingMode
3279 public java.math.BigDecimal getRoundingIncrement() {
3280 if (roundingIncrementICU == null)
3282 return roundingIncrementICU.toBigDecimal();
3286 * {@icu} Sets the rounding increment. In the absence of a rounding increment, numbers
3287 * will be rounded to the number of digits displayed.
3289 * @param newValue A positive rounding increment, or <code>null</code> or
3290 * <code>BigDecimal(0.0)</code> to use the default rounding increment.
3291 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0
3292 * @see #getRoundingIncrement
3293 * @see #getRoundingMode
3294 * @see #setRoundingMode
3297 public void setRoundingIncrement(java.math.BigDecimal newValue) {
3298 if (newValue == null) {
3299 setRoundingIncrement((BigDecimal) null);
3301 setRoundingIncrement(new BigDecimal(newValue));
3306 * {@icu} Sets the rounding increment. In the absence of a rounding increment, numbers
3307 * will be rounded to the number of digits displayed.
3309 * @param newValue A positive rounding increment, or <code>null</code> or
3310 * <code>BigDecimal(0.0)</code> to use the default rounding increment.
3311 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0
3312 * @see #getRoundingIncrement
3313 * @see #getRoundingMode
3314 * @see #setRoundingMode
3317 public void setRoundingIncrement(BigDecimal newValue) {
3318 int i = newValue == null ? 0 : newValue.compareTo(BigDecimal.ZERO);
3320 throw new IllegalArgumentException("Illegal rounding increment");
3323 setInternalRoundingIncrement(null);
3325 setInternalRoundingIncrement(newValue);
3327 resetActualRounding();
3331 * {@icu} Sets the rounding increment. In the absence of a rounding increment, numbers
3332 * will be rounded to the number of digits displayed.
3334 * @param newValue A positive rounding increment, or 0.0 to use the default
3335 * rounding increment.
3336 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0
3337 * @see #getRoundingIncrement
3338 * @see #getRoundingMode
3339 * @see #setRoundingMode
3342 public void setRoundingIncrement(double newValue) {
3343 if (newValue < 0.0) {
3344 throw new IllegalArgumentException("Illegal rounding increment");
3346 if (newValue == 0.0d) {
3347 setInternalRoundingIncrement((BigDecimal) null);
3349 // Should use BigDecimal#valueOf(double) instead of constructor
3350 // to avoid the double precision problem.
3351 setInternalRoundingIncrement(BigDecimal.valueOf(newValue));
3353 resetActualRounding();
3357 * Returns the rounding mode.
3359 * @return A rounding mode, between <code>BigDecimal.ROUND_UP</code> and
3360 * <code>BigDecimal.ROUND_UNNECESSARY</code>.
3361 * @see #setRoundingIncrement
3362 * @see #getRoundingIncrement
3363 * @see #setRoundingMode
3364 * @see java.math.BigDecimal
3368 public int getRoundingMode() {
3369 return roundingMode;
3373 * Sets the rounding mode. This has no effect unless the rounding increment is greater
3376 * @param roundingMode A rounding mode, between <code>BigDecimal.ROUND_UP</code> and
3377 * <code>BigDecimal.ROUND_UNNECESSARY</code>.
3378 * @exception IllegalArgumentException if <code>roundingMode</code> is unrecognized.
3379 * @see #setRoundingIncrement
3380 * @see #getRoundingIncrement
3381 * @see #getRoundingMode
3382 * @see java.math.BigDecimal
3386 public void setRoundingMode(int roundingMode) {
3387 if (roundingMode < BigDecimal.ROUND_UP || roundingMode > BigDecimal.ROUND_UNNECESSARY) {
3388 throw new IllegalArgumentException("Invalid rounding mode: " + roundingMode);
3391 this.roundingMode = roundingMode;
3392 resetActualRounding();
3396 * Returns the width to which the output of <code>format()</code> is padded. The width is
3397 * counted in 16-bit code units.
3399 * @return the format width, or zero if no padding is in effect
3400 * @see #setFormatWidth
3401 * @see #getPadCharacter
3402 * @see #setPadCharacter
3403 * @see #getPadPosition
3404 * @see #setPadPosition
3407 public int getFormatWidth() {
3412 * Sets the width to which the output of <code>format()</code> is
3413 * padded. The width is counted in 16-bit code units. This method
3414 * also controls whether padding is enabled.
3416 * @param width the width to which to pad the result of
3417 * <code>format()</code>, or zero to disable padding
3418 * @exception IllegalArgumentException if <code>width</code> is < 0
3419 * @see #getFormatWidth
3420 * @see #getPadCharacter
3421 * @see #setPadCharacter
3422 * @see #getPadPosition
3423 * @see #setPadPosition
3426 public void setFormatWidth(int width) {
3428 throw new IllegalArgumentException("Illegal format width");
3430 formatWidth = width;
3434 * {@icu} Returns the character used to pad to the format width. The default is ' '.
3436 * @return the pad character
3437 * @see #setFormatWidth
3438 * @see #getFormatWidth
3439 * @see #setPadCharacter
3440 * @see #getPadPosition
3441 * @see #setPadPosition
3444 public char getPadCharacter() {
3449 * {@icu} Sets the character used to pad to the format width. If padding is not
3450 * enabled, then this will take effect if padding is later enabled.
3452 * @param padChar the pad character
3453 * @see #setFormatWidth
3454 * @see #getFormatWidth
3455 * @see #getPadCharacter
3456 * @see #getPadPosition
3457 * @see #setPadPosition
3460 public void setPadCharacter(char padChar) {
3465 * {@icu} Returns the position at which padding will take place. This is the location at
3466 * which padding will be inserted if the result of <code>format()</code> is shorter
3467 * than the format width.
3469 * @return the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
3470 * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
3471 * <code>PAD_AFTER_SUFFIX</code>.
3472 * @see #setFormatWidth
3473 * @see #getFormatWidth
3474 * @see #setPadCharacter
3475 * @see #getPadCharacter
3476 * @see #setPadPosition
3477 * @see #PAD_BEFORE_PREFIX
3478 * @see #PAD_AFTER_PREFIX
3479 * @see #PAD_BEFORE_SUFFIX
3480 * @see #PAD_AFTER_SUFFIX
3483 public int getPadPosition() {
3488 * {@icu} Sets the position at which padding will take place. This is the location at
3489 * which padding will be inserted if the result of <code>format()</code> is shorter
3490 * than the format width. This has no effect unless padding is enabled.
3492 * @param padPos the pad position, one of <code>PAD_BEFORE_PREFIX</code>,
3493 * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or
3494 * <code>PAD_AFTER_SUFFIX</code>.
3495 * @exception IllegalArgumentException if the pad position in unrecognized
3496 * @see #setFormatWidth
3497 * @see #getFormatWidth
3498 * @see #setPadCharacter
3499 * @see #getPadCharacter
3500 * @see #getPadPosition
3501 * @see #PAD_BEFORE_PREFIX
3502 * @see #PAD_AFTER_PREFIX
3503 * @see #PAD_BEFORE_SUFFIX
3504 * @see #PAD_AFTER_SUFFIX
3507 public void setPadPosition(int padPos) {
3508 if (padPos < PAD_BEFORE_PREFIX || padPos > PAD_AFTER_SUFFIX) {
3509 throw new IllegalArgumentException("Illegal pad position");
3511 padPosition = padPos;
3515 * {@icu} Returns whether or not scientific notation is used.
3517 * @return true if this object formats and parses scientific notation
3518 * @see #setScientificNotation
3519 * @see #getMinimumExponentDigits
3520 * @see #setMinimumExponentDigits
3521 * @see #isExponentSignAlwaysShown
3522 * @see #setExponentSignAlwaysShown
3525 public boolean isScientificNotation() {
3526 return useExponentialNotation;
3530 * {@icu} Sets whether or not scientific notation is used. When scientific notation is
3531 * used, the effective maximum number of integer digits is <= 8. If the maximum number
3532 * of integer digits is set to more than 8, the effective maximum will be 1. This
3533 * allows this call to generate a 'default' scientific number format without
3534 * additional changes.
3536 * @param useScientific true if this object formats and parses scientific notation
3537 * @see #isScientificNotation
3538 * @see #getMinimumExponentDigits
3539 * @see #setMinimumExponentDigits
3540 * @see #isExponentSignAlwaysShown
3541 * @see #setExponentSignAlwaysShown
3544 public void setScientificNotation(boolean useScientific) {
3545 useExponentialNotation = useScientific;
3549 * {@icu} Returns the minimum exponent digits that will be shown.
3551 * @return the minimum exponent digits that will be shown
3552 * @see #setScientificNotation
3553 * @see #isScientificNotation
3554 * @see #setMinimumExponentDigits
3555 * @see #isExponentSignAlwaysShown
3556 * @see #setExponentSignAlwaysShown
3559 public byte getMinimumExponentDigits() {
3560 return minExponentDigits;
3564 * {@icu} Sets the minimum exponent digits that will be shown. This has no effect
3565 * unless scientific notation is in use.
3567 * @param minExpDig a value >= 1 indicating the fewest exponent
3568 * digits that will be shown
3569 * @exception IllegalArgumentException if <code>minExpDig</code> < 1
3570 * @see #setScientificNotation
3571 * @see #isScientificNotation
3572 * @see #getMinimumExponentDigits
3573 * @see #isExponentSignAlwaysShown
3574 * @see #setExponentSignAlwaysShown
3577 public void setMinimumExponentDigits(byte minExpDig) {
3578 if (minExpDig < 1) {
3579 throw new IllegalArgumentException("Exponent digits must be >= 1");
3581 minExponentDigits = minExpDig;
3585 * {@icu} Returns whether the exponent sign is always shown.
3587 * @return true if the exponent is always prefixed with either the localized minus
3588 * sign or the localized plus sign, false if only negative exponents are prefixed with
3589 * the localized minus sign.
3590 * @see #setScientificNotation
3591 * @see #isScientificNotation
3592 * @see #setMinimumExponentDigits
3593 * @see #getMinimumExponentDigits
3594 * @see #setExponentSignAlwaysShown
3597 public boolean isExponentSignAlwaysShown() {
3598 return exponentSignAlwaysShown;
3602 * {@icu} Sets whether the exponent sign is always shown. This has no effect unless
3603 * scientific notation is in use.
3605 * @param expSignAlways true if the exponent is always prefixed with either the
3606 * localized minus sign or the localized plus sign, false if only negative exponents
3607 * are prefixed with the localized minus sign.
3608 * @see #setScientificNotation
3609 * @see #isScientificNotation
3610 * @see #setMinimumExponentDigits
3611 * @see #getMinimumExponentDigits
3612 * @see #isExponentSignAlwaysShown
3615 public void setExponentSignAlwaysShown(boolean expSignAlways) {
3616 exponentSignAlwaysShown = expSignAlways;
3620 * Returns the grouping size. Grouping size is the number of digits between grouping
3621 * separators in the integer portion of a number. For example, in the number
3622 * "123,456.78", the grouping size is 3.
3624 * @see #setGroupingSize
3625 * @see NumberFormat#isGroupingUsed
3626 * @see DecimalFormatSymbols#getGroupingSeparator
3629 public int getGroupingSize() {
3630 return groupingSize;
3634 * Sets the grouping size. Grouping size is the number of digits between grouping
3635 * separators in the integer portion of a number. For example, in the number
3636 * "123,456.78", the grouping size is 3.
3638 * @see #getGroupingSize
3639 * @see NumberFormat#setGroupingUsed
3640 * @see DecimalFormatSymbols#setGroupingSeparator
3643 public void setGroupingSize(int newValue) {
3644 groupingSize = (byte) newValue;
3648 * {@icu} Returns the secondary grouping size. In some locales one grouping interval
3649 * is used for the least significant integer digits (the primary grouping size), and
3650 * another is used for all others (the secondary grouping size). A formatter
3651 * supporting a secondary grouping size will return a positive integer unequal to the
3652 * primary grouping size returned by <code>getGroupingSize()</code>. For example, if
3653 * the primary grouping size is 4, and the secondary grouping size is 2, then the
3654 * number 123456789 formats as "1,23,45,6789", and the pattern appears as "#,##,###0".
3656 * @return the secondary grouping size, or a value less than one if there is none
3657 * @see #setSecondaryGroupingSize
3658 * @see NumberFormat#isGroupingUsed
3659 * @see DecimalFormatSymbols#getGroupingSeparator
3662 public int getSecondaryGroupingSize() {
3663 return groupingSize2;
3667 * {@icu} Sets the secondary grouping size. If set to a value less than 1, then
3668 * secondary grouping is turned off, and the primary grouping size is used for all
3669 * intervals, not just the least significant.
3671 * @see #getSecondaryGroupingSize
3672 * @see NumberFormat#setGroupingUsed
3673 * @see DecimalFormatSymbols#setGroupingSeparator
3676 public void setSecondaryGroupingSize(int newValue) {
3677 groupingSize2 = (byte) newValue;
3681 * {@icu} Returns the MathContext used by this format.
3683 * @return desired MathContext
3684 * @see #getMathContext
3687 public MathContext getMathContextICU() {
3692 * {@icu} Returns the MathContext used by this format.
3694 * @return desired MathContext
3695 * @see #getMathContext
3698 public java.math.MathContext getMathContext() {
3700 // don't allow multiple references
3701 return mathContext == null ? null : new java.math.MathContext(mathContext.getDigits(),
3702 java.math.RoundingMode.valueOf(mathContext.getRoundingMode()));
3703 } catch (Exception foo) {
3704 return null; // should never happen
3709 * {@icu} Sets the MathContext used by this format.
3711 * @param newValue desired MathContext
3712 * @see #getMathContext
3715 public void setMathContextICU(MathContext newValue) {
3716 mathContext = newValue;
3720 * {@icu} Sets the MathContext used by this format.
3722 * @param newValue desired MathContext
3723 * @see #getMathContext
3726 public void setMathContext(java.math.MathContext newValue) {
3727 mathContext = new MathContext(newValue.getPrecision(), MathContext.SCIENTIFIC, false,
3728 (newValue.getRoundingMode()).ordinal());
3732 * Returns the behavior of the decimal separator with integers. (The decimal
3733 * separator will always appear with decimals.) <p> Example: Decimal ON: 12345 ->
3734 * 12345.; OFF: 12345 -> 12345
3738 public boolean isDecimalSeparatorAlwaysShown() {
3739 return decimalSeparatorAlwaysShown;
3743 * Sets the behavior of the decimal separator with integers. (The decimal separator
3744 * will always appear with decimals.)
3746 * <p>This only affects formatting, and only where there might be no digits after the
3747 * decimal point, e.g., if true, 3456.00 -> "3,456." if false, 3456.00 -> "3456" This
3748 * is independent of parsing. If you want parsing to stop at the decimal point, use
3749 * setParseIntegerOnly.
3752 * Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
3756 public void setDecimalSeparatorAlwaysShown(boolean newValue) {
3757 decimalSeparatorAlwaysShown = newValue;
3761 * {@icu} Returns a copy of the CurrencyPluralInfo used by this format. It might
3762 * return null if the decimal format is not a plural type currency decimal
3763 * format. Plural type currency decimal format means either the pattern in the decimal
3764 * format contains 3 currency signs, or the decimal format is initialized with
3765 * PLURALCURRENCYSTYLE.
3767 * @return desired CurrencyPluralInfo
3768 * @see CurrencyPluralInfo
3771 public CurrencyPluralInfo getCurrencyPluralInfo() {
3773 // don't allow multiple references
3774 return currencyPluralInfo == null ? null :
3775 (CurrencyPluralInfo) currencyPluralInfo.clone();
3776 } catch (Exception foo) {
3777 return null; // should never happen
3782 * {@icu} Sets the CurrencyPluralInfo used by this format. The format uses a copy of
3783 * the provided information.
3785 * @param newInfo desired CurrencyPluralInfo
3786 * @see CurrencyPluralInfo
3789 public void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) {
3790 currencyPluralInfo = (CurrencyPluralInfo) newInfo.clone();
3791 isReadyForParsing = false;
3799 public Object clone() {
3801 DecimalFormat other = (DecimalFormat) super.clone();
3802 other.symbols = (DecimalFormatSymbols) symbols.clone();
3803 other.digitList = new DigitList(); // fix for JB#5358
3804 if (currencyPluralInfo != null) {
3805 other.currencyPluralInfo = (CurrencyPluralInfo) currencyPluralInfo.clone();
3807 other.attributes = new ArrayList<FieldPosition>(); // #9240
3809 // TODO: We need to figure out whether we share a single copy of DigitList by
3810 // multiple cloned copies. format/subformat are designed to use a single
3811 // instance, but parse/subparse implementation is not.
3813 } catch (Exception e) {
3814 throw new IllegalStateException();
3823 public boolean equals(Object obj) {
3826 if (!super.equals(obj))
3827 return false; // super does class check
3829 DecimalFormat other = (DecimalFormat) obj;
3830 // Add the comparison of the four new added fields ,they are posPrefixPattern,
3831 // posSuffixPattern, negPrefixPattern, negSuffixPattern. [Richard/GCL]
3832 // following are added to accomodate changes for currency plural format.
3833 return currencySignCount == other.currencySignCount
3834 && (style != NumberFormat.PLURALCURRENCYSTYLE ||
3835 equals(posPrefixPattern, other.posPrefixPattern)
3836 && equals(posSuffixPattern, other.posSuffixPattern)
3837 && equals(negPrefixPattern, other.negPrefixPattern)
3838 && equals(negSuffixPattern, other.negSuffixPattern))
3839 && multiplier == other.multiplier
3840 && groupingSize == other.groupingSize
3841 && groupingSize2 == other.groupingSize2
3842 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
3843 && useExponentialNotation == other.useExponentialNotation
3844 && (!useExponentialNotation || minExponentDigits == other.minExponentDigits)
3845 && useSignificantDigits == other.useSignificantDigits
3846 && (!useSignificantDigits || minSignificantDigits == other.minSignificantDigits
3847 && maxSignificantDigits == other.maxSignificantDigits)
3848 && symbols.equals(other.symbols)
3849 && Utility.objectEquals(currencyPluralInfo, other.currencyPluralInfo);
3852 // method to unquote the strings and compare
3853 private boolean equals(String pat1, String pat2) {
3854 if (pat1 == null || pat2 == null) {
3855 return (pat1 == null && pat2 == null);
3858 if (pat1.equals(pat2)) {
3861 return unquote(pat1).equals(unquote(pat2));
3864 private String unquote(String pat) {
3865 StringBuilder buf = new StringBuilder(pat.length());
3867 while (i < pat.length()) {
3868 char ch = pat.charAt(i++);
3873 return buf.toString();
3876 // protected void handleToString(StringBuffer buf) {
3877 // buf.append("\nposPrefixPattern: '" + posPrefixPattern + "'\n");
3878 // buf.append("positivePrefix: '" + positivePrefix + "'\n");
3879 // buf.append("posSuffixPattern: '" + posSuffixPattern + "'\n");
3880 // buf.append("positiveSuffix: '" + positiveSuffix + "'\n");
3881 // buf.append("negPrefixPattern: '" +
3882 // com.ibm.icu.impl.Utility.format1ForSource(negPrefixPattern) + "'\n");
3883 // buf.append("negativePrefix: '" +
3884 // com.ibm.icu.impl.Utility.format1ForSource(negativePrefix) + "'\n");
3885 // buf.append("negSuffixPattern: '" + negSuffixPattern + "'\n");
3886 // buf.append("negativeSuffix: '" + negativeSuffix + "'\n");
3887 // buf.append("multiplier: '" + multiplier + "'\n");
3888 // buf.append("groupingSize: '" + groupingSize + "'\n");
3889 // buf.append("groupingSize2: '" + groupingSize2 + "'\n");
3890 // buf.append("decimalSeparatorAlwaysShown: '" + decimalSeparatorAlwaysShown + "'\n");
3891 // buf.append("useExponentialNotation: '" + useExponentialNotation + "'\n");
3892 // buf.append("minExponentDigits: '" + minExponentDigits + "'\n");
3893 // buf.append("useSignificantDigits: '" + useSignificantDigits + "'\n");
3894 // buf.append("minSignificantDigits: '" + minSignificantDigits + "'\n");
3895 // buf.append("maxSignificantDigits: '" + maxSignificantDigits + "'\n");
3896 // buf.append("symbols: '" + symbols + "'");
3900 * Overrides hashCode.
3904 public int hashCode() {
3905 return super.hashCode() * 37 + positivePrefix.hashCode();
3906 // just enough fields for a reasonable distribution
3910 * Synthesizes a pattern string that represents the current state of this Format
3913 * @see #applyPattern
3916 public String toPattern() {
3917 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
3918 // the prefix or suffix pattern might not be defined yet, so they can not be
3919 // synthesized, instead, get them directly. but it might not be the actual
3920 // pattern used in formatting. the actual pattern used in formatting depends
3921 // on the formatted number's plural count.
3922 return formatPattern;
3924 return toPattern(false);
3928 * Synthesizes a localized pattern string that represents the current state of this
3931 * @see #applyPattern
3934 public String toLocalizedPattern() {
3935 if (style == NumberFormat.PLURALCURRENCYSTYLE) {
3936 return formatPattern;
3938 return toPattern(true);
3942 * Expands the affix pattern strings into the expanded affix strings. If any affix
3943 * pattern string is null, do not expand it. This method should be called any time the
3944 * symbols or the affix patterns change in order to keep the expanded affix strings up
3945 * to date. This method also will be called before formatting if format currency
3946 * plural names, since the plural name is not a static one, it is based on the
3947 * currency plural count, the affix will be known only after the currency plural count
3948 * is know. In which case, the parameter 'pluralCount' will be a non-null currency
3949 * plural count. In all other cases, the 'pluralCount' is null, which means it is not
3952 // Bug 4212072 [Richard/GCL]
3953 private void expandAffixes(String pluralCount) {
3954 // expandAffix() will set currencyChoice to a non-null value if
3955 // appropriate AND if it is null.
3956 currencyChoice = null;
3958 // Reuse one StringBuffer for better performance
3959 StringBuffer buffer = new StringBuffer();
3960 if (posPrefixPattern != null) {
3961 expandAffix(posPrefixPattern, pluralCount, buffer, false);
3962 positivePrefix = buffer.toString();
3964 if (posSuffixPattern != null) {
3965 expandAffix(posSuffixPattern, pluralCount, buffer, false);
3966 positiveSuffix = buffer.toString();
3968 if (negPrefixPattern != null) {
3969 expandAffix(negPrefixPattern, pluralCount, buffer, false);
3970 negativePrefix = buffer.toString();
3972 if (negSuffixPattern != null) {
3973 expandAffix(negSuffixPattern, pluralCount, buffer, false);
3974 negativeSuffix = buffer.toString();
3979 * Expands an affix pattern into an affix string. All characters in the pattern are
3980 * literal unless bracketed by QUOTEs. The following characters outside QUOTE are
3981 * recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, PATTERN_MINUS, and
3982 * CURRENCY_SIGN. If CURRENCY_SIGN is doubled, it is interpreted as an international
3983 * currency sign. If CURRENCY_SIGN is tripled, it is interpreted as currency plural
3984 * long names, such as "US Dollars". Any other character outside QUOTE represents
3985 * itself. Quoted text must be well-formed.
3987 * This method is used in two distinct ways. First, it is used to expand the stored
3988 * affix patterns into actual affixes. For this usage, doFormat must be false. Second,
3989 * it is used to expand the stored affix patterns given a specific number (doFormat ==
3990 * true), for those rare cases in which a currency format references a ChoiceFormat
3991 * (e.g., en_IN display name for INR). The number itself is taken from digitList.
3993 * When used in the first way, this method has a side effect: It sets currencyChoice
3994 * to a ChoiceFormat object, if the currency's display name in this locale is a
3995 * ChoiceFormat pattern (very rare). It only does this if currencyChoice is null to
3998 * @param pattern the non-null, possibly empty pattern
3999 * @param pluralCount the plural count. It is only used for currency plural format. In
4000 * which case, it is the plural count of the currency amount. For example, in en_US,
4001 * it is the singular "one", or the plural "other". For all other cases, it is null,
4002 * and is not being used.
4003 * @param buffer a scratch StringBuffer; its contents will be lost
4004 * @param doFormat if false, then the pattern will be expanded, and if a currency
4005 * symbol is encountered that expands to a ChoiceFormat, the currencyChoice member
4006 * variable will be initialized if it is null. If doFormat is true, then it is assumed
4007 * that the currencyChoice has been created, and it will be used to format the value
4010 // Bug 4212072 [Richard/GCL]
4011 private void expandAffix(String pattern, String pluralCount, StringBuffer buffer,
4013 buffer.setLength(0);
4014 for (int i = 0; i < pattern.length();) {
4015 char c = pattern.charAt(i++);
4018 int j = pattern.indexOf(QUOTE, i);
4020 buffer.append(QUOTE);
4024 buffer.append(pattern.substring(i, j));
4026 if (i < pattern.length() && pattern.charAt(i) == QUOTE) {
4027 buffer.append(QUOTE);
4034 // Unterminated quote; should be caught by apply
4036 throw new RuntimeException();
4044 // As of ICU 2.2 we use the currency object, and ignore the currency
4045 // symbols in the DFS, unless we have a null currency object. This occurs
4046 // if resurrecting a pre-2.2 object or if the user sets a custom DFS.
4047 boolean intl = i < pattern.length() && pattern.charAt(i) == CURRENCY_SIGN;
4048 boolean plural = false;
4051 if (i < pattern.length() && pattern.charAt(i) == CURRENCY_SIGN) {
4058 Currency currency = getCurrency();
4059 if (currency != null) {
4060 // plural name is only needed when pluralCount != null, which means
4061 // when formatting currency plural names. For other cases,
4062 // pluralCount == null, and plural names are not needed.
4063 if (plural && pluralCount != null) {
4064 boolean isChoiceFormat[] = new boolean[1];
4065 s = currency.getName(symbols.getULocale(), Currency.PLURAL_LONG_NAME,
4066 pluralCount, isChoiceFormat);
4068 boolean isChoiceFormat[] = new boolean[1];
4069 s = currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME,
4071 if (isChoiceFormat[0]) {
4072 // Two modes here: If doFormat is false, we set up
4073 // currencyChoice. If doFormat is true, we use the previously
4074 // created currencyChoice to format the value in digitList.
4076 // If the currency is handled by a ChoiceFormat, then
4077 // we're not going to use the expanded
4078 // patterns. Instantiate the ChoiceFormat and return.
4079 if (currencyChoice == null) {
4080 currencyChoice = new ChoiceFormat(s);
4082 // We could almost return null or "" here, since the
4083 // expanded affixes are almost not used at all in this
4084 // situation. However, one method -- toPattern() -- still
4085 // does use the expanded affixes, in order to set up a
4086 // padding pattern. We use the CURRENCY_SIGN as a
4088 s = String.valueOf(CURRENCY_SIGN);
4090 FieldPosition pos = new FieldPosition(0); // ignored
4091 currencyChoice.format(digitList.getDouble(), buffer, pos);
4096 s = currency.getCurrencyCode();
4099 s = intl ? symbols.getInternationalCurrencySymbol() :
4100 symbols.getCurrencySymbol();
4104 case PATTERN_PERCENT:
4105 c = symbols.getPercent();
4107 case PATTERN_PER_MILLE:
4108 c = symbols.getPerMill();
4111 String minusString = symbols.getMinusString();
4112 buffer.append(minusString);
4120 * Append an affix to the given StringBuffer.
4123 * buffer to append to
4127 private int appendAffix(StringBuffer buf, boolean isNegative, boolean isPrefix,
4128 boolean parseAttr) {
4129 if (currencyChoice != null) {
4130 String affixPat = null;
4132 affixPat = isNegative ? negPrefixPattern : posPrefixPattern;
4134 affixPat = isNegative ? negSuffixPattern : posSuffixPattern;
4136 StringBuffer affixBuf = new StringBuffer();
4137 expandAffix(affixPat, null, affixBuf, true);
4138 buf.append(affixBuf);
4139 return affixBuf.length();
4142 String affix = null;
4144 affix = isNegative ? negativePrefix : positivePrefix;
4146 affix = isNegative ? negativeSuffix : positiveSuffix;
4148 // [Spark/CDL] Invoke formatAffix2Attribute to add attributes for affix
4150 int offset = affix.indexOf(symbols.getCurrencySymbol());
4152 offset = affix.indexOf(symbols.getPercent());
4157 formatAffix2Attribute(affix, buf.length() + offset, buf.length() + affix.length());
4160 return affix.length();
4164 * [Spark/CDL] This is a newly added method, used to add attributes for prefix and
4167 private void formatAffix2Attribute(String affix, int begin, int end) {
4168 // [Spark/CDL] It is the invoker's responsibility to ensure that, before the
4169 // invocation of this method, attributes is not null. if( attributes == null )
4171 if (affix.indexOf(symbols.getCurrencySymbol()) > -1) {
4172 addAttribute(Field.CURRENCY, begin, end);
4173 } else if (affix.indexOf(symbols.getMinusSign()) > -1) {
4174 addAttribute(Field.SIGN, begin, end);
4175 } else if (affix.indexOf(symbols.getPercent()) > -1) {
4176 addAttribute(Field.PERCENT, begin, end);
4177 } else if (affix.indexOf(symbols.getPerMill()) > -1) {
4178 addAttribute(Field.PERMILLE, begin, end);
4183 * [Spark/CDL] Use this method to add attribute.
4185 private void addAttribute(Field field, int begin, int end) {
4186 FieldPosition pos = new FieldPosition(field);
4187 pos.setBeginIndex(begin);
4188 pos.setEndIndex(end);
4189 attributes.add(pos);
4193 * Formats the object to an attributed string, and return the corresponding iterator.
4198 public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
4199 return formatToCharacterIterator(obj, NULL_UNIT);
4202 AttributedCharacterIterator formatToCharacterIterator(Object obj, Unit unit) {
4203 if (!(obj instanceof Number))
4204 throw new IllegalArgumentException();
4205 Number number = (Number) obj;
4206 StringBuffer text = new StringBuffer();
4207 unit.writePrefix(text);
4209 if (obj instanceof BigInteger) {
4210 format((BigInteger) number, text, new FieldPosition(0), true);
4211 } else if (obj instanceof java.math.BigDecimal) {
4212 format((java.math.BigDecimal) number, text, new FieldPosition(0)
4214 } else if (obj instanceof Double) {
4215 format(number.doubleValue(), text, new FieldPosition(0), true);
4216 } else if (obj instanceof Integer || obj instanceof Long) {
4217 format(number.longValue(), text, new FieldPosition(0), true);
4219 throw new IllegalArgumentException();
4221 unit.writeSuffix(text);
4222 AttributedString as = new AttributedString(text.toString());
4224 // add NumberFormat field attributes to the AttributedString
4225 for (int i = 0; i < attributes.size(); i++) {
4226 FieldPosition pos = attributes.get(i);
4227 Format.Field attribute = pos.getFieldAttribute();
4228 as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos.getEndIndex());
4231 // return the CharacterIterator from AttributedString
4232 return as.getIterator();
4236 * Appends an affix pattern to the given StringBuffer. Localize unquoted specials.
4238 private void appendAffixPattern(StringBuffer buffer, boolean isNegative, boolean isPrefix,
4239 boolean localized) {
4240 String affixPat = null;
4242 affixPat = isNegative ? negPrefixPattern : posPrefixPattern;
4244 affixPat = isNegative ? negSuffixPattern : posSuffixPattern;
4247 // When there is a null affix pattern, we use the affix itself.
4248 if (affixPat == null) {
4249 String affix = null;
4251 affix = isNegative ? negativePrefix : positivePrefix;
4253 affix = isNegative ? negativeSuffix : positiveSuffix;
4255 // Do this crudely for now: Wrap everything in quotes.
4256 buffer.append(QUOTE);
4257 for (int i = 0; i < affix.length(); ++i) {
4258 char ch = affix.charAt(i);
4264 buffer.append(QUOTE);
4269 buffer.append(affixPat);
4272 for (i = 0; i < affixPat.length(); ++i) {
4273 char ch = affixPat.charAt(i);
4276 j = affixPat.indexOf(QUOTE, i + 1);
4278 throw new IllegalArgumentException("Malformed affix pattern: " + affixPat);
4280 buffer.append(affixPat.substring(i, j + 1));
4283 case PATTERN_PER_MILLE:
4284 ch = symbols.getPerMill();
4286 case PATTERN_PERCENT:
4287 ch = symbols.getPercent();
4290 ch = symbols.getMinusSign();
4293 // check if char is same as any other symbol
4294 if (ch == symbols.getDecimalSeparator() || ch == symbols.getGroupingSeparator()) {
4295 buffer.append(QUOTE);
4297 buffer.append(QUOTE);
4306 * Does the real work of generating a pattern.
4308 private String toPattern(boolean localized) {
4309 StringBuffer result = new StringBuffer();
4310 char zero = localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT;
4311 char digit = localized ? symbols.getDigit() : PATTERN_DIGIT;
4313 boolean useSigDig = areSignificantDigitsUsed();
4315 sigDigit = localized ? symbols.getSignificantDigit() : PATTERN_SIGNIFICANT_DIGIT;
4317 char group = localized ? symbols.getGroupingSeparator() : PATTERN_GROUPING_SEPARATOR;
4319 int roundingDecimalPos = 0; // Pos of decimal in roundingDigits
4320 String roundingDigits = null;
4321 int padPos = (formatWidth > 0) ? padPosition : -1;
4322 String padSpec = (formatWidth > 0)
4323 ? new StringBuffer(2).append(localized
4324 ? symbols.getPadEscape()
4325 : PATTERN_PAD_ESCAPE).append(pad).toString()
4327 if (roundingIncrementICU != null) {
4328 i = roundingIncrementICU.scale();
4329 roundingDigits = roundingIncrementICU.movePointRight(i).toString();
4330 roundingDecimalPos = roundingDigits.length() - i;
4332 for (int part = 0; part < 2; ++part) {
4333 // variable not used int partStart = result.length();
4334 if (padPos == PAD_BEFORE_PREFIX) {
4335 result.append(padSpec);
4338 // Use original symbols read from resources in pattern eg. use "\u00A4"
4339 // instead of "$" in Locale.US [Richard/GCL]
4340 appendAffixPattern(result, part != 0, true, localized);
4341 if (padPos == PAD_AFTER_PREFIX) {
4342 result.append(padSpec);
4344 int sub0Start = result.length();
4345 int g = isGroupingUsed() ? Math.max(0, groupingSize) : 0;
4346 if (g > 0 && groupingSize2 > 0 && groupingSize2 != groupingSize) {
4349 int maxDig = 0, minDig = 0, maxSigDig = 0;
4351 minDig = getMinimumSignificantDigits();
4352 maxDig = maxSigDig = getMaximumSignificantDigits();
4354 minDig = getMinimumIntegerDigits();
4355 maxDig = getMaximumIntegerDigits();
4357 if (useExponentialNotation) {
4358 if (maxDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
4361 } else if (useSigDig) {
4362 maxDig = Math.max(maxDig, g + 1);
4364 maxDig = Math.max(Math.max(g, getMinimumIntegerDigits()), roundingDecimalPos) + 1;
4366 for (i = maxDig; i > 0; --i) {
4367 if (!useExponentialNotation && i < maxDig && isGroupingPosition(i)) {
4368 result.append(group);
4371 // #@,@### (maxSigDig == 5, minSigDig == 2) 65 4321 (1-based pos,
4372 // count from the right) Use # if pos > maxSigDig or 1 <= pos <=
4373 // (maxSigDig - minSigDig) Use @ if (maxSigDig - minSigDig) < pos <=
4375 result.append((maxSigDig >= i && i > (maxSigDig - minDig)) ? sigDigit : digit);
4377 if (roundingDigits != null) {
4378 int pos = roundingDecimalPos - i;
4379 if (pos >= 0 && pos < roundingDigits.length()) {
4380 result.append((char) (roundingDigits.charAt(pos) - '0' + zero));
4384 result.append(i <= minDig ? zero : digit);
4388 if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) {
4389 result.append(localized ? symbols.getDecimalSeparator() :
4390 PATTERN_DECIMAL_SEPARATOR);
4392 int pos = roundingDecimalPos;
4393 for (i = 0; i < getMaximumFractionDigits(); ++i) {
4394 if (roundingDigits != null && pos < roundingDigits.length()) {
4395 result.append(pos < 0 ? zero :
4396 (char) (roundingDigits.charAt(pos) - '0' + zero));
4400 result.append(i < getMinimumFractionDigits() ? zero : digit);
4403 if (useExponentialNotation) {
4405 result.append(symbols.getExponentSeparator());
4407 result.append(PATTERN_EXPONENT);
4409 if (exponentSignAlwaysShown) {
4410 result.append(localized ? symbols.getPlusSign() : PATTERN_PLUS_SIGN);
4412 for (i = 0; i < minExponentDigits; ++i) {
4413 result.append(zero);
4416 if (padSpec != null && !useExponentialNotation) {
4417 int add = formatWidth
4421 ? positivePrefix.length() + positiveSuffix.length()
4422 : negativePrefix.length() + negativeSuffix.length());
4424 result.insert(sub0Start, digit);
4427 // Only add a grouping separator if we have at least 2 additional
4428 // characters to be added, so we don't end up with ",###".
4429 if (add > 1 && isGroupingPosition(maxDig)) {
4430 result.insert(sub0Start, group);
4435 if (padPos == PAD_BEFORE_SUFFIX) {
4436 result.append(padSpec);
4438 // Use original symbols read from resources in pattern eg. use "\u00A4"
4439 // instead of "$" in Locale.US [Richard/GCL]
4440 appendAffixPattern(result, part != 0, false, localized);
4441 if (padPos == PAD_AFTER_SUFFIX) {
4442 result.append(padSpec);
4445 if (negativeSuffix.equals(positiveSuffix) &&
4446 negativePrefix.equals(PATTERN_MINUS + positivePrefix)) {
4449 result.append(localized ? symbols.getPatternSeparator() : PATTERN_SEPARATOR);
4453 return result.toString();
4457 * Applies the given pattern to this Format object. A pattern is a short-hand
4458 * specification for the various formatting properties. These properties can also be
4459 * changed individually through the various setter methods.
4461 * <p>There is no limit to integer digits are set by this routine, since that is the
4462 * typical end-user desire; use setMaximumInteger if you want to set a real value. For
4463 * negative numbers, use a second pattern, separated by a semicolon
4465 * <p>Example "#,#00.0#" -> 1,234.56
4467 * <p>This means a minimum of 2 integer digits, 1 fraction digit, and a maximum of 2
4470 * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parentheses.
4472 * <p>In negative patterns, the minimum and maximum counts are ignored; these are
4473 * presumed to be set in the positive pattern.
4477 public void applyPattern(String pattern) {
4478 applyPattern(pattern, false);
4482 * Applies the given pattern to this Format object. The pattern is assumed to be in a
4483 * localized notation. A pattern is a short-hand specification for the various
4484 * formatting properties. These properties can also be changed individually through
4485 * the various setter methods.
4487 * <p>There is no limit to integer digits are set by this routine, since that is the
4488 * typical end-user desire; use setMaximumInteger if you want to set a real value. For
4489 * negative numbers, use a second pattern, separated by a semicolon
4491 * <p>Example "#,#00.0#" -> 1,234.56
4493 * <p>This means a minimum of 2 integer digits, 1 fraction digit, and a maximum of 2
4496 * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
4498 * <p>In negative patterns, the minimum and maximum counts are ignored; these are
4499 * presumed to be set in the positive pattern.
4503 public void applyLocalizedPattern(String pattern) {
4504 applyPattern(pattern, true);
4508 * Does the real work of applying a pattern.
4510 private void applyPattern(String pattern, boolean localized) {
4511 applyPatternWithoutExpandAffix(pattern, localized);
4512 expandAffixAdjustWidth(null);
4515 private void expandAffixAdjustWidth(String pluralCount) {
4516 // Bug 4212072 Update the affix strings according to symbols in order to keep the
4517 // affix strings up to date. [Richard/GCL]
4518 expandAffixes(pluralCount);
4520 // Now that we have the actual prefix and suffix, fix up formatWidth
4521 if (formatWidth > 0) {
4522 formatWidth += positivePrefix.length() + positiveSuffix.length();
4526 private void applyPatternWithoutExpandAffix(String pattern, boolean localized) {
4527 char zeroDigit = PATTERN_ZERO_DIGIT; // '0'
4528 char sigDigit = PATTERN_SIGNIFICANT_DIGIT; // '@'
4529 char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
4530 char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
4531 char percent = PATTERN_PERCENT;
4532 char perMill = PATTERN_PER_MILLE;
4533 char digit = PATTERN_DIGIT; // '#'
4534 char separator = PATTERN_SEPARATOR;
4535 String exponent = String.valueOf(PATTERN_EXPONENT);
4536 char plus = PATTERN_PLUS_SIGN;
4537 char padEscape = PATTERN_PAD_ESCAPE;
4538 char minus = PATTERN_MINUS; // Bug 4212072 [Richard/GCL]
4540 zeroDigit = symbols.getZeroDigit();
4541 sigDigit = symbols.getSignificantDigit();
4542 groupingSeparator = symbols.getGroupingSeparator();
4543 decimalSeparator = symbols.getDecimalSeparator();
4544 percent = symbols.getPercent();
4545 perMill = symbols.getPerMill();
4546 digit = symbols.getDigit();
4547 separator = symbols.getPatternSeparator();
4548 exponent = symbols.getExponentSeparator();
4549 plus = symbols.getPlusSign();
4550 padEscape = symbols.getPadEscape();
4551 minus = symbols.getMinusSign(); // Bug 4212072 [Richard/GCL]
4553 char nineDigit = (char) (zeroDigit + 9);
4555 boolean gotNegative = false;
4558 // Part 0 is the positive pattern. Part 1, if present, is the negative
4560 for (int part = 0; part < 2 && pos < pattern.length(); ++part) {
4561 // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix, 2=suffix,
4562 // 3=prefix in quote, 4=suffix in quote. Subpart 0 is between the prefix and
4563 // suffix, and consists of pattern characters. In the prefix and suffix,
4564 // percent, permille, and currency symbols are recognized and translated.
4565 int subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
4567 // It's important that we don't change any fields of this object
4568 // prematurely. We set the following variables for the multiplier, grouping,
4569 // etc., and then only change the actual object fields if everything parses
4570 // correctly. This also lets us register the data from part 0 and ignore the
4571 // part 1, except for the prefix and suffix.
4572 StringBuilder prefix = new StringBuilder();
4573 StringBuilder suffix = new StringBuilder();
4574 int decimalPos = -1;
4576 int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
4577 byte groupingCount = -1;
4578 byte groupingCount2 = -1;
4581 int incrementPos = -1;
4582 long incrementVal = 0;
4583 byte expDigits = -1;
4584 boolean expSignAlways = false;
4585 int currencySignCnt = 0;
4587 // The affix is either the prefix or the suffix.
4588 StringBuilder affix = prefix;
4592 PARTLOOP: for (; pos < pattern.length(); ++pos) {
4593 char ch = pattern.charAt(pos);
4595 case 0: // Pattern proper subpart (between prefix & suffix)
4596 // Process the digits, decimal, and grouping characters. We record
4597 // five pieces of information. We expect the digits to occur in the
4598 // pattern ####00.00####, and we record the number of left digits,
4599 // zero (central) digits, and right digits. The position of the last
4600 // grouping character is recorded (should be somewhere within the
4601 // first two blocks of characters), as is the position of the decimal
4602 // point, if any (should be in the zero digits). If there is no
4603 // decimal point, then there should be no right digits.
4605 if (zeroDigitCount > 0 || sigDigitCount > 0) {
4610 if (groupingCount >= 0 && decimalPos < 0) {
4613 } else if ((ch >= zeroDigit && ch <= nineDigit) || ch == sigDigit) {
4614 if (digitRightCount > 0) {
4615 patternError("Unexpected '" + ch + '\'', pattern);
4617 if (ch == sigDigit) {
4621 if (ch != zeroDigit) {
4622 int p = digitLeftCount + zeroDigitCount + digitRightCount;
4623 if (incrementPos >= 0) {
4624 while (incrementPos < p) {
4631 incrementVal += ch - zeroDigit;
4634 if (groupingCount >= 0 && decimalPos < 0) {
4637 } else if (ch == groupingSeparator) {
4638 // Bug 4212072 process the Localized pattern like
4639 // "'Fr. '#'##0.05;'Fr.-'#'##0.05" (Locale="CH", groupingSeparator
4640 // == QUOTE) [Richard/GCL]
4641 if (ch == QUOTE && (pos + 1) < pattern.length()) {
4642 char after = pattern.charAt(pos + 1);
4643 if (!(after == digit || (after >= zeroDigit && after <= nineDigit))) {
4644 // A quote outside quotes indicates either the opening
4645 // quote or two quotes, which is a quote literal. That is,
4646 // we have the first quote in 'do' or o''clock.
4647 if (after == QUOTE) {
4649 // Fall through to append(ch)
4651 if (groupingCount < 0) {
4652 subpart = 3; // quoted prefix subpart
4654 // Transition to suffix subpart
4655 subpart = 2; // suffix subpart
4664 if (decimalPos >= 0) {
4665 patternError("Grouping separator after decimal", pattern);
4667 groupingCount2 = groupingCount;
4669 } else if (ch == decimalSeparator) {
4670 if (decimalPos >= 0) {
4671 patternError("Multiple decimal separators", pattern);
4673 // Intentionally incorporate the digitRightCount, even though it
4674 // is illegal for this to be > 0 at this point. We check pattern
4676 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
4678 if (pattern.regionMatches(pos, exponent, 0, exponent.length())) {
4679 if (expDigits >= 0) {
4680 patternError("Multiple exponential symbols", pattern);
4682 if (groupingCount >= 0) {
4683 patternError("Grouping separator in exponential", pattern);
4685 pos += exponent.length();
4686 // Check for positive prefix
4687 if (pos < pattern.length() && pattern.charAt(pos) == plus) {
4688 expSignAlways = true;
4691 // Use lookahead to parse out the exponential part of the
4692 // pattern, then jump into suffix subpart.
4694 while (pos < pattern.length() && pattern.charAt(pos) == zeroDigit) {
4699 // 1. Require at least one mantissa pattern digit
4700 // 2. Disallow "#+ @" in mantissa
4701 // 3. Require at least one exponent pattern digit
4702 if (((digitLeftCount + zeroDigitCount) < 1 &&
4703 (sigDigitCount + digitRightCount) < 1)
4704 || (sigDigitCount > 0 && digitLeftCount > 0) || expDigits < 1) {
4705 patternError("Malformed exponential", pattern);
4708 // Transition to suffix subpart
4709 subpart = 2; // suffix subpart
4711 sub0Limit = pos--; // backup: for() will increment
4715 case 1: // Prefix subpart
4716 case 2: // Suffix subpart
4717 // Process the prefix / suffix characters Process unquoted characters
4718 // seen in prefix or suffix subpart.
4720 // Several syntax characters implicitly begins the next subpart if we
4721 // are in the prefix; otherwise they are illegal if unquoted.
4722 if (ch == digit || ch == groupingSeparator || ch == decimalSeparator
4723 || (ch >= zeroDigit && ch <= nineDigit) || ch == sigDigit) {
4724 // Any of these characters implicitly begins the
4725 // next subpart if we are in the prefix
4726 if (subpart == 1) { // prefix subpart
4727 subpart = 0; // pattern proper subpart
4728 sub0Start = pos--; // Reprocess this character
4730 } else if (ch == QUOTE) {
4731 // Bug 4212072 process the Localized pattern like
4732 // "'Fr. '#'##0.05;'Fr.-'#'##0.05" (Locale="CH",
4733 // groupingSeparator == QUOTE) [Richard/GCL]
4735 // A quote outside quotes indicates either the opening quote
4736 // or two quotes, which is a quote literal. That is, we have
4737 // the first quote in 'do' or o''clock.
4738 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) {
4742 subpart += 2; // open quote
4746 patternError("Unquoted special character '" + ch + '\'', pattern);
4747 } else if (ch == CURRENCY_SIGN) {
4748 // Use lookahead to determine if the currency sign is
4750 boolean doubled = (pos + 1) < pattern.length() &&
4751 pattern.charAt(pos + 1) == CURRENCY_SIGN;
4753 // Bug 4212072 To meet the need of expandAffix(String,
4754 // StirngBuffer) [Richard/GCL]
4756 ++pos; // Skip over the doubled character
4757 affix.append(ch); // append two: one here, one below
4758 if ((pos + 1) < pattern.length() &&
4759 pattern.charAt(pos + 1) == CURRENCY_SIGN) {
4760 ++pos; // Skip over the tripled character
4761 affix.append(ch); // append again
4762 currencySignCnt = CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT;
4764 currencySignCnt = CURRENCY_SIGN_COUNT_IN_ISO_FORMAT;
4767 currencySignCnt = CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT;
4769 // Fall through to append(ch)
4770 } else if (ch == QUOTE) {
4771 // A quote outside quotes indicates either the opening quote or
4772 // two quotes, which is a quote literal. That is, we have the
4773 // first quote in 'do' or o''clock.
4774 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) {
4776 affix.append(ch); // append two: one here, one below
4778 subpart += 2; // open quote
4780 // Fall through to append(ch)
4781 } else if (ch == separator) {
4782 // Don't allow separators in the prefix, and don't allow
4783 // separators in the second pattern (part == 1).
4784 if (subpart == 1 || part == 1) {
4785 patternError("Unquoted special character '" + ch + '\'', pattern);
4788 break PARTLOOP; // Go to next part
4789 } else if (ch == percent || ch == perMill) {
4790 // Next handle characters which are appended directly.
4792 patternError("Too many percent/permille characters", pattern);
4794 multpl = (ch == percent) ? 100 : 1000;
4795 // Convert to non-localized pattern
4796 ch = (ch == percent) ? PATTERN_PERCENT : PATTERN_PER_MILLE;
4797 // Fall through to append(ch)
4798 } else if (ch == minus) {
4799 // Convert to non-localized pattern
4801 // Fall through to append(ch)
4802 } else if (ch == padEscape) {
4804 patternError("Multiple pad specifiers", pattern);
4806 if ((pos + 1) == pattern.length()) {
4807 patternError("Invalid pad specifier", pattern);
4809 padPos = pos++; // Advance past pad char
4810 padChar = pattern.charAt(pos);
4815 case 3: // Prefix subpart, in quote
4816 case 4: // Suffix subpart, in quote
4817 // A quote within quotes indicates either the closing quote or two
4818 // quotes, which is a quote literal. That is, we have the second quote
4819 // in 'do' or 'don''t'.
4821 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) {
4825 subpart -= 2; // close quote
4827 // Fall through to append(ch)
4829 // NOTE: In ICU 2.2 there was code here to parse quoted percent and
4830 // permille characters _within quotes_ and give them special
4831 // meaning. This is incorrect, since quoted characters are literals
4832 // without special meaning.
4838 if (subpart == 3 || subpart == 4) {
4839 patternError("Unterminated quote", pattern);
4842 if (sub0Limit == 0) {
4843 sub0Limit = pattern.length();
4846 if (sub2Limit == 0) {
4847 sub2Limit = pattern.length();
4850 // Handle patterns with no '0' pattern character. These patterns are legal,
4851 // but must be recodified to make sense. "##.###" -> "#0.###". ".###" ->
4854 // We allow patterns of the form "####" to produce a zeroDigitCount of zero
4855 // (got that?); although this seems like it might make it possible for
4856 // format() to produce empty strings, format() checks for this condition and
4857 // outputs a zero digit in this situation. Having a zeroDigitCount of zero
4858 // yields a minimum integer digits of zero, which allows proper round-trip
4859 // patterns. We don't want "#" to become "#0" when toPattern() is called (even
4860 // though that's what it really is, semantically).
4861 if (zeroDigitCount == 0 && sigDigitCount == 0 &&
4862 digitLeftCount > 0 && decimalPos >= 0) {
4863 // Handle "###.###" and "###." and ".###"
4866 ++n; // Handle ".###"
4867 digitRightCount = digitLeftCount - n;
4868 digitLeftCount = n - 1;
4872 // Do syntax checking on the digits, decimal points, and quotes.
4873 if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0)
4875 && (sigDigitCount > 0
4876 || decimalPos < digitLeftCount
4877 || decimalPos > (digitLeftCount + zeroDigitCount)))
4878 || groupingCount == 0
4879 || groupingCount2 == 0
4880 || (sigDigitCount > 0 && zeroDigitCount > 0)
4881 || subpart > 2) { // subpart > 2 == unmatched quote
4882 patternError("Malformed pattern", pattern);
4885 // Make sure pad is at legal position before or after affix.
4887 if (padPos == start) {
4888 padPos = PAD_BEFORE_PREFIX;
4889 } else if (padPos + 2 == sub0Start) {
4890 padPos = PAD_AFTER_PREFIX;
4891 } else if (padPos == sub0Limit) {
4892 padPos = PAD_BEFORE_SUFFIX;
4893 } else if (padPos + 2 == sub2Limit) {
4894 padPos = PAD_AFTER_SUFFIX;
4896 patternError("Illegal pad position", pattern);
4901 // Set negative affixes temporarily to match the positive
4902 // affixes. Fix this up later after processing both parts.
4904 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer)
4906 posPrefixPattern = negPrefixPattern = prefix.toString();
4907 posSuffixPattern = negSuffixPattern = suffix.toString();
4909 useExponentialNotation = (expDigits >= 0);
4910 if (useExponentialNotation) {
4911 minExponentDigits = expDigits;
4912 exponentSignAlwaysShown = expSignAlways;
4914 int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
4915 // The effectiveDecimalPos is the position the decimal is at or would be
4916 // at if there is no decimal. Note that if decimalPos<0, then
4917 // digitTotalCount == digitLeftCount + zeroDigitCount.
4918 int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
4919 boolean useSigDig = (sigDigitCount > 0);
4920 setSignificantDigitsUsed(useSigDig);
4922 setMinimumSignificantDigits(sigDigitCount);
4923 setMaximumSignificantDigits(sigDigitCount + digitRightCount);
4925 int minInt = effectiveDecimalPos - digitLeftCount;
4926 setMinimumIntegerDigits(minInt);
4928 // Upper limit on integer and fraction digits for a Java double
4930 setMaximumIntegerDigits(useExponentialNotation ? digitLeftCount + minInt :
4931 DOUBLE_INTEGER_DIGITS);
4932 _setMaximumFractionDigits(decimalPos >= 0 ?
4933 (digitTotalCount - decimalPos) : 0);
4934 setMinimumFractionDigits(decimalPos >= 0 ?
4935 (digitLeftCount + zeroDigitCount - decimalPos) : 0);
4937 setGroupingUsed(groupingCount > 0);
4938 this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
4939 this.groupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
4940 ? groupingCount2 : 0;
4941 this.multiplier = multpl;
4942 setDecimalSeparatorAlwaysShown(decimalPos == 0 || decimalPos == digitTotalCount);
4944 padPosition = padPos;
4945 formatWidth = sub0Limit - sub0Start; // to be fixed up below
4950 if (incrementVal != 0) {
4951 // BigDecimal scale cannot be negative (even though this makes perfect
4952 // sense), so we need to handle this.
4953 int scale = incrementPos - effectiveDecimalPos;
4954 roundingIncrementICU = BigDecimal.valueOf(incrementVal, scale > 0 ? scale : 0);
4956 roundingIncrementICU = roundingIncrementICU.movePointRight(-scale);
4958 roundingMode = BigDecimal.ROUND_HALF_EVEN;
4960 setRoundingIncrement((BigDecimal) null);
4963 // Update currency sign count for the new pattern
4964 currencySignCount = currencySignCnt;
4966 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer)
4968 negPrefixPattern = prefix.toString();
4969 negSuffixPattern = suffix.toString();
4975 // Bug 4140009 Process the empty pattern [Richard/GCL]
4976 if (pattern.length() == 0) {
4977 posPrefixPattern = posSuffixPattern = "";
4978 setMinimumIntegerDigits(0);
4979 setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
4980 setMinimumFractionDigits(0);
4981 _setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
4984 // If there was no negative pattern, or if the negative pattern is identical to
4985 // the positive pattern, then prepend the minus sign to the positive pattern to
4986 // form the negative pattern.
4988 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer) [Richard/GCL]
4991 (negPrefixPattern.equals(posPrefixPattern)
4992 && negSuffixPattern.equals(posSuffixPattern))) {
4993 negSuffixPattern = posSuffixPattern;
4994 negPrefixPattern = PATTERN_MINUS + posPrefixPattern;
4996 setLocale(null, null);
4998 formatPattern = pattern;
5000 // special handlings for currency instance
5001 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) {
5002 // reset rounding increment and max/min fractional digits
5004 Currency theCurrency = getCurrency();
5005 if (theCurrency != null) {
5006 setRoundingIncrement(theCurrency.getRoundingIncrement());
5007 int d = theCurrency.getDefaultFractionDigits();
5008 setMinimumFractionDigits(d);
5009 _setMaximumFractionDigits(d);
5012 // initialize currencyPluralInfo if needed
5013 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT
5014 && currencyPluralInfo == null) {
5015 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale());
5018 resetActualRounding();
5022 private void patternError(String msg, String pattern) {
5023 throw new IllegalArgumentException(msg + " in pattern \"" + pattern + '"');
5027 // Rewrite the following 4 "set" methods Upper limit on integer and fraction digits
5028 // for a Java double [Richard/GCL]
5031 * Sets the maximum number of digits allowed in the integer portion of a number. This
5032 * override limits the integer digit count to 309.
5034 * @see NumberFormat#setMaximumIntegerDigits
5038 public void setMaximumIntegerDigits(int newValue) {
5039 super.setMaximumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
5043 * Sets the minimum number of digits allowed in the integer portion of a number. This
5044 * override limits the integer digit count to 309.
5046 * @see NumberFormat#setMinimumIntegerDigits
5050 public void setMinimumIntegerDigits(int newValue) {
5051 super.setMinimumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS));
5055 * {@icu} Returns the minimum number of significant digits that will be
5056 * displayed. This value has no effect unless {@link #areSignificantDigitsUsed()}
5059 * @return the fewest significant digits that will be shown
5062 public int getMinimumSignificantDigits() {
5063 return minSignificantDigits;
5067 * {@icu} Returns the maximum number of significant digits that will be
5068 * displayed. This value has no effect unless {@link #areSignificantDigitsUsed()}
5071 * @return the most significant digits that will be shown
5074 public int getMaximumSignificantDigits() {
5075 return maxSignificantDigits;
5079 * {@icu} Sets the minimum number of significant digits that will be displayed. If
5080 * <code>min</code> is less than one then it is set to one. If the maximum significant
5081 * digits count is less than <code>min</code>, then it is set to <code>min</code>.
5082 * This function also enables the use of significant digits by this formatter -
5083 * {@link #areSignificantDigitsUsed()} will return true.
5085 * @param min the fewest significant digits to be shown
5088 public void setMinimumSignificantDigits(int min) {
5092 // pin max sig dig to >= min
5093 int max = Math.max(maxSignificantDigits, min);
5094 minSignificantDigits = min;
5095 maxSignificantDigits = max;
5096 setSignificantDigitsUsed(true);
5100 * {@icu} Sets the maximum number of significant digits that will be displayed. If
5101 * <code>max</code> is less than one then it is set to one. If the minimum significant
5102 * digits count is greater than <code>max</code>, then it is set to <code>max</code>.
5103 * This function also enables the use of significant digits by this formatter -
5104 * {@link #areSignificantDigitsUsed()} will return true.
5106 * @param max the most significant digits to be shown
5109 public void setMaximumSignificantDigits(int max) {
5113 // pin min sig dig to 1..max
5114 int min = Math.min(minSignificantDigits, max);
5115 minSignificantDigits = min;
5116 maxSignificantDigits = max;
5117 setSignificantDigitsUsed(true);
5121 * {@icu} Returns true if significant digits are in use or false if integer and
5122 * fraction digit counts are in use.
5124 * @return true if significant digits are in use
5127 public boolean areSignificantDigitsUsed() {
5128 return useSignificantDigits;
5132 * {@icu} Sets whether significant digits are in use, or integer and fraction digit
5133 * counts are in use.
5135 * @param useSignificantDigits true to use significant digits, or false to use integer
5136 * and fraction digit counts
5139 public void setSignificantDigitsUsed(boolean useSignificantDigits) {
5140 this.useSignificantDigits = useSignificantDigits;
5144 * Sets the <tt>Currency</tt> object used to display currency amounts. This takes
5145 * effect immediately, if this format is a currency format. If this format is not a
5146 * currency format, then the currency object is used if and when this object becomes a
5147 * currency format through the application of a new pattern.
5149 * @param theCurrency new currency object to use. Must not be null.
5153 public void setCurrency(Currency theCurrency) {
5154 // If we are a currency format, then modify our affixes to
5155 // encode the currency symbol for the given currency in our
5156 // locale, and adjust the decimal digits and rounding for the
5159 super.setCurrency(theCurrency);
5160 if (theCurrency != null) {
5161 boolean[] isChoiceFormat = new boolean[1];
5162 String s = theCurrency.getName(symbols.getULocale(),
5163 Currency.SYMBOL_NAME, isChoiceFormat);
5164 symbols.setCurrency(theCurrency);
5165 symbols.setCurrencySymbol(s);
5168 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) {
5169 if (theCurrency != null) {
5170 setRoundingIncrement(theCurrency.getRoundingIncrement());
5171 int d = theCurrency.getDefaultFractionDigits();
5172 setMinimumFractionDigits(d);
5173 setMaximumFractionDigits(d);
5175 if (currencySignCount != CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) {
5176 // This is not necessary for plural format type
5177 // because affixes will be resolved in subformat
5178 expandAffixes(null);
5184 * Returns the currency in effect for this formatter. Subclasses should override this
5185 * method as needed. Unlike getCurrency(), this method should never return null.
5188 * @deprecated This API is ICU internal only.
5192 protected Currency getEffectiveCurrency() {
5193 Currency c = getCurrency();
5195 c = Currency.getInstance(symbols.getInternationalCurrencySymbol());
5201 * Sets the maximum number of digits allowed in the fraction portion of a number. This
5202 * override limits the fraction digit count to 340.
5204 * @see NumberFormat#setMaximumFractionDigits
5208 public void setMaximumFractionDigits(int newValue) {
5209 _setMaximumFractionDigits(newValue);
5210 resetActualRounding();
5214 * Internal method for DecimalFormat, setting maximum fractional digits
5215 * without triggering actual rounding recalculated.
5217 private void _setMaximumFractionDigits(int newValue) {
5218 super.setMaximumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
5222 * Sets the minimum number of digits allowed in the fraction portion of a number. This
5223 * override limits the fraction digit count to 340.
5225 * @see NumberFormat#setMinimumFractionDigits
5229 public void setMinimumFractionDigits(int newValue) {
5230 super.setMinimumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS));
5234 * Sets whether {@link #parse(String, ParsePosition)} returns BigDecimal. The
5235 * default value is false.
5237 * @param value true if {@link #parse(String, ParsePosition)}
5238 * returns BigDecimal.
5241 public void setParseBigDecimal(boolean value) {
5242 parseBigDecimal = value;
5246 * Returns whether {@link #parse(String, ParsePosition)} returns BigDecimal.
5248 * @return true if {@link #parse(String, ParsePosition)} returns BigDecimal.
5251 public boolean isParseBigDecimal() {
5252 return parseBigDecimal;
5256 * Set the maximum number of exponent digits when parsing a number.
5257 * If the limit is set too high, an OutOfMemoryException may be triggered.
5258 * The default value is 1000.
5259 * @param newValue the new limit
5261 * @provisional This API might change or be removed in a future release.
5263 public void setParseMaxDigits(int newValue) {
5265 PARSE_MAX_EXPONENT = newValue;
5270 * Get the current maximum number of exponent digits when parsing a
5274 * @provisional This API might change or be removed in a future release.
5276 public int getParseMaxDigits() {
5277 return PARSE_MAX_EXPONENT;
5280 private void writeObject(ObjectOutputStream stream) throws IOException {
5281 // Ticket#6449 Format.Field instances are not serializable. When
5282 // formatToCharacterIterator is called, attributes (ArrayList) stores
5283 // FieldPosition instances with NumberFormat.Field. Because NumberFormat.Field is
5284 // not serializable, we need to clear the contents of the list when writeObject is
5285 // called. We could remove the field or make it transient, but it will break
5286 // serialization compatibility.
5289 stream.defaultWriteObject();
5293 * First, read the default serializable fields from the stream. Then if
5294 * <code>serialVersionOnStream</code> is less than 1, indicating that the stream was
5295 * written by JDK 1.1, initialize <code>useExponentialNotation</code> to false, since
5296 * it was not present in JDK 1.1. Finally, set serialVersionOnStream back to the
5297 * maximum allowed value so that default serialization will work properly if this
5298 * object is streamed out again.
5300 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
5301 stream.defaultReadObject();
5303 // Bug 4185761 validate fields [Richard/GCL]
5305 // We only need to check the maximum counts because NumberFormat .readObject has
5306 // already ensured that the maximum is greater than the minimum count.
5308 // Commented for compatibility with previous version, and reserved for further use
5309 // if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
5310 // getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { throw new
5311 // InvalidObjectException("Digit count out of range"); }
5314 // Truncate the maximumIntegerDigits to DOUBLE_INTEGER_DIGITS and
5315 // maximumFractionDigits to DOUBLE_FRACTION_DIGITS
5317 if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS) {
5318 setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS);
5320 if (getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
5321 _setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS);
5323 if (serialVersionOnStream < 2) {
5324 exponentSignAlwaysShown = false;
5325 setInternalRoundingIncrement(null);
5326 roundingMode = BigDecimal.ROUND_HALF_EVEN;
5329 padPosition = PAD_BEFORE_PREFIX;
5330 if (serialVersionOnStream < 1) {
5331 // Didn't have exponential fields
5332 useExponentialNotation = false;
5335 if (serialVersionOnStream < 3) {
5336 // Versions prior to 3 do not store a currency object. Create one to match
5337 // the DecimalFormatSymbols object.
5338 setCurrencyForSymbols();
5340 serialVersionOnStream = currentSerialVersion;
5341 digitList = new DigitList();
5343 if (roundingIncrement != null) {
5344 setInternalRoundingIncrement(new BigDecimal(roundingIncrement));
5346 resetActualRounding();
5349 private void setInternalRoundingIncrement(BigDecimal value) {
5350 roundingIncrementICU = value;
5351 roundingIncrement = value == null ? null : value.toBigDecimal();
5354 // ----------------------------------------------------------------------
5355 // INSTANCE VARIABLES
5356 // ----------------------------------------------------------------------
5358 private transient DigitList digitList = new DigitList();
5361 * The symbol used as a prefix when formatting positive numbers, e.g. "+".
5364 * @see #getPositivePrefix
5366 private String positivePrefix = "";
5369 * The symbol used as a suffix when formatting positive numbers. This is often an
5373 * @see #getPositiveSuffix
5375 private String positiveSuffix = "";
5378 * The symbol used as a prefix when formatting negative numbers, e.g. "-".
5381 * @see #getNegativePrefix
5383 private String negativePrefix = "-";
5386 * The symbol used as a suffix when formatting negative numbers. This is often an
5390 * @see #getNegativeSuffix
5392 private String negativeSuffix = "";
5395 * The prefix pattern for non-negative numbers. This variable corresponds to
5396 * <code>positivePrefix</code>.
5398 * <p>This pattern is expanded by the method <code>expandAffix()</code> to
5399 * <code>positivePrefix</code> to update the latter to reflect changes in
5400 * <code>symbols</code>. If this variable is <code>null</code> then
5401 * <code>positivePrefix</code> is taken as a literal value that does not change when
5402 * <code>symbols</code> changes. This variable is always <code>null</code> for
5403 * <code>DecimalFormat</code> objects older than stream version 2 restored from
5409 private String posPrefixPattern;
5412 * The suffix pattern for non-negative numbers. This variable corresponds to
5413 * <code>positiveSuffix</code>. This variable is analogous to
5414 * <code>posPrefixPattern</code>; see that variable for further documentation.
5419 private String posSuffixPattern;
5422 * The prefix pattern for negative numbers. This variable corresponds to
5423 * <code>negativePrefix</code>. This variable is analogous to
5424 * <code>posPrefixPattern</code>; see that variable for further documentation.
5429 private String negPrefixPattern;
5432 * The suffix pattern for negative numbers. This variable corresponds to
5433 * <code>negativeSuffix</code>. This variable is analogous to
5434 * <code>posPrefixPattern</code>; see that variable for further documentation.
5439 private String negSuffixPattern;
5442 * Formatter for ChoiceFormat-based currency names. If this field is not null, then
5443 * delegate to it to format currency symbols.
5447 private ChoiceFormat currencyChoice;
5450 * The multiplier for use in percent, permill, etc.
5453 * @see #getMultiplier
5455 private int multiplier = 1;
5458 * The number of digits between grouping separators in the integer portion of a
5459 * number. Must be greater than 0 if <code>NumberFormat.groupingUsed</code> is true.
5462 * @see #getGroupingSize
5463 * @see NumberFormat#isGroupingUsed
5465 private byte groupingSize = 3; // invariant, > 0 if useThousands
5468 * The secondary grouping size. This is only used for Hindi numerals, which use a
5469 * primary grouping of 3 and a secondary grouping of 2, e.g., "12,34,567". If this
5470 * value is less than 1, then secondary grouping is equal to the primary grouping.
5473 private byte groupingSize2 = 0;
5476 * If true, forces the decimal separator to always appear in a formatted number, even
5477 * if the fractional part of the number is zero.
5480 * @see #isDecimalSeparatorAlwaysShown
5482 private boolean decimalSeparatorAlwaysShown = false;
5485 * The <code>DecimalFormatSymbols</code> object used by this format. It contains the
5486 * symbols used to format numbers, e.g. the grouping separator, decimal separator, and
5490 * @see #setDecimalFormatSymbols
5491 * @see DecimalFormatSymbols
5493 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
5496 * True to use significant digits rather than integer and fraction digit counts.
5501 private boolean useSignificantDigits = false;
5504 * The minimum number of significant digits to show. Must be >= 1 and <=
5505 * maxSignificantDigits. Ignored unless useSignificantDigits == true.
5510 private int minSignificantDigits = 1;
5513 * The maximum number of significant digits to show. Must be >=
5514 * minSignficantDigits. Ignored unless useSignificantDigits == true.
5519 private int maxSignificantDigits = 6;
5522 * True to force the use of exponential (i.e. scientific) notation
5523 * when formatting numbers.
5525 *<p> Note that the JDK 1.2 public API provides no way to set this
5526 * field, even though it is supported by the implementation and
5527 * the stream format. The intent is that this will be added to the
5528 * API in the future.
5532 private boolean useExponentialNotation; // Newly persistent in JDK 1.2
5535 * The minimum number of digits used to display the exponent when a number is
5536 * formatted in exponential notation. This field is ignored if
5537 * <code>useExponentialNotation</code> is not true.
5539 * <p>Note that the JDK 1.2 public API provides no way to set this field, even though
5540 * it is supported by the implementation and the stream format. The intent is that
5541 * this will be added to the API in the future.
5545 private byte minExponentDigits; // Newly persistent in JDK 1.2
5548 * If true, the exponent is always prefixed with either the plus sign or the minus
5549 * sign. Otherwise, only negative exponents are prefixed with the minus sign. This has
5550 * no effect unless <code>useExponentialNotation</code> is true.
5553 * @since AlphaWorks NumberFormat
5555 private boolean exponentSignAlwaysShown = false;
5558 * The value to which numbers are rounded during formatting. For example, if the
5559 * rounding increment is 0.05, then 13.371 would be formatted as 13.350, assuming 3
5560 * fraction digits. Has the value <code>null</code> if rounding is not in effect, or a
5561 * positive value if rounding is in effect. Default value <code>null</code>.
5564 * @since AlphaWorks NumberFormat
5566 // Note: this is kept in sync with roundingIncrementICU.
5567 // it is only kept around to avoid a conversion when formatting a java.math.BigDecimal
5568 private java.math.BigDecimal roundingIncrement = null;
5571 * The value to which numbers are rounded during formatting. For example, if the
5572 * rounding increment is 0.05, then 13.371 would be formatted as 13.350, assuming 3
5573 * fraction digits. Has the value <code>null</code> if rounding is not in effect, or a
5574 * positive value if rounding is in effect. Default value <code>null</code>. WARNING:
5575 * the roundingIncrement value is the one serialized.
5578 * @since AlphaWorks NumberFormat
5580 private transient BigDecimal roundingIncrementICU = null;
5583 * The rounding mode. This value controls any rounding operations which occur when
5584 * applying a rounding increment or when reducing the number of fraction digits to
5585 * satisfy a maximum fraction digits limit. The value may assume any of the
5586 * <code>BigDecimal</code> rounding mode values. Default value
5587 * <code>BigDecimal.ROUND_HALF_EVEN</code>.
5590 * @since AlphaWorks NumberFormat
5592 private int roundingMode = BigDecimal.ROUND_HALF_EVEN;
5595 * Operations on <code>BigDecimal</code> numbers are controlled by a {@link
5596 * MathContext} object, which provides the context (precision and other information)
5597 * for the operation. The default <code>MathContext</code> settings are
5598 * <code>digits=0, form=PLAIN, lostDigits=false, roundingMode=ROUND_HALF_UP</code>;
5599 * these settings perform fixed point arithmetic with unlimited precision, as defined
5600 * for the original BigDecimal class in Java 1.1 and Java 1.2
5602 // context for plain unlimited math
5603 private MathContext mathContext = new MathContext(0, MathContext.PLAIN);
5606 * The padded format width, or zero if there is no padding. Must be >= 0. Default
5610 * @since AlphaWorks NumberFormat
5612 private int formatWidth = 0;
5615 * The character used to pad the result of format to <code>formatWidth</code>, if
5616 * padding is in effect. Default value ' '.
5619 * @since AlphaWorks NumberFormat
5621 private char pad = ' ';
5624 * The position in the string at which the <code>pad</code> character will be
5625 * inserted, if padding is in effect. Must have a value from
5626 * <code>PAD_BEFORE_PREFIX</code> to <code>PAD_AFTER_SUFFIX</code>. Default value
5627 * <code>PAD_BEFORE_PREFIX</code>.
5630 * @since AlphaWorks NumberFormat
5632 private int padPosition = PAD_BEFORE_PREFIX;
5635 * True if {@link #parse(String, ParsePosition)} to return BigDecimal rather than
5636 * Long, Double or BigDecimal except special values. This property is introduced for
5637 * J2SE 5 compatibility support.
5641 * @see #setParseBigDecimal(boolean)
5642 * @see #isParseBigDecimal()
5644 private boolean parseBigDecimal = false;
5646 // ----------------------------------------------------------------------
5648 static final int currentSerialVersion = 3;
5651 * The internal serial version which says which version was written Possible values
5656 * <li><b>0</b> (default): versions before JDK 1.2
5658 * <li><b>1</b>: version from JDK 1.2 and later, which includes the two new fields
5659 * <code>useExponentialNotation</code> and <code>minExponentDigits</code>.
5661 * <li><b>2</b>: version on AlphaWorks, which adds roundingMode, formatWidth, pad,
5662 * padPosition, exponentSignAlwaysShown, roundingIncrement.
5664 * <li><b>3</b>: ICU 2.2. Adds currency object.
5670 private int serialVersionOnStream = currentSerialVersion;
5672 // ----------------------------------------------------------------------
5674 // ----------------------------------------------------------------------
5677 * {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to
5678 * specify pad characters inserted before the prefix.
5680 * @see #setPadPosition
5681 * @see #getPadPosition
5682 * @see #PAD_AFTER_PREFIX
5683 * @see #PAD_BEFORE_SUFFIX
5684 * @see #PAD_AFTER_SUFFIX
5687 public static final int PAD_BEFORE_PREFIX = 0;
5690 * {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to
5691 * specify pad characters inserted after the prefix.
5693 * @see #setPadPosition
5694 * @see #getPadPosition
5695 * @see #PAD_BEFORE_PREFIX
5696 * @see #PAD_BEFORE_SUFFIX
5697 * @see #PAD_AFTER_SUFFIX
5700 public static final int PAD_AFTER_PREFIX = 1;
5703 * {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to
5704 * specify pad characters inserted before the suffix.
5706 * @see #setPadPosition
5707 * @see #getPadPosition
5708 * @see #PAD_BEFORE_PREFIX
5709 * @see #PAD_AFTER_PREFIX
5710 * @see #PAD_AFTER_SUFFIX
5713 public static final int PAD_BEFORE_SUFFIX = 2;
5716 * {@icu} Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to
5717 * specify pad characters inserted after the suffix.
5719 * @see #setPadPosition
5720 * @see #getPadPosition
5721 * @see #PAD_BEFORE_PREFIX
5722 * @see #PAD_AFTER_PREFIX
5723 * @see #PAD_BEFORE_SUFFIX
5726 public static final int PAD_AFTER_SUFFIX = 3;
5728 // Constants for characters used in programmatic (unlocalized) patterns.
5729 static final char PATTERN_ZERO_DIGIT = '0';
5730 static final char PATTERN_ONE_DIGIT = '1';
5731 static final char PATTERN_TWO_DIGIT = '2';
5732 static final char PATTERN_THREE_DIGIT = '3';
5733 static final char PATTERN_FOUR_DIGIT = '4';
5734 static final char PATTERN_FIVE_DIGIT = '5';
5735 static final char PATTERN_SIX_DIGIT = '6';
5736 static final char PATTERN_SEVEN_DIGIT = '7';
5737 static final char PATTERN_EIGHT_DIGIT = '8';
5738 static final char PATTERN_NINE_DIGIT = '9';
5739 static final char PATTERN_GROUPING_SEPARATOR = ',';
5740 static final char PATTERN_DECIMAL_SEPARATOR = '.';
5741 static final char PATTERN_DIGIT = '#';
5742 static final char PATTERN_SIGNIFICANT_DIGIT = '@';
5743 static final char PATTERN_EXPONENT = 'E';
5744 static final char PATTERN_PLUS_SIGN = '+';
5747 private static final char PATTERN_PER_MILLE = '\u2030';
5748 private static final char PATTERN_PERCENT = '%';
5749 static final char PATTERN_PAD_ESCAPE = '*';
5751 * Bug 4212072 To meet the need of expandAffix(String, StirngBuffer) [Richard/GCL]
5753 private static final char PATTERN_MINUS = '-';
5756 private static final char PATTERN_SEPARATOR = ';';
5758 // Pad escape is package private to allow access by DecimalFormatSymbols.
5759 // Also plus sign. Also exponent.
5762 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It is used in
5763 * patterns and substitued with either the currency symbol, or if it is doubled, with
5764 * the international currency symbol. If the CURRENCY_SIGN is seen in a pattern, then
5765 * the decimal separator is replaced with the monetary decimal separator.
5767 * The CURRENCY_SIGN is not localized.
5769 private static final char CURRENCY_SIGN = '\u00A4';
5771 private static final char QUOTE = '\'';
5774 * Upper limit on integer and fraction digits for a Java double [Richard/GCL]
5776 static final int DOUBLE_INTEGER_DIGITS = 309;
5777 static final int DOUBLE_FRACTION_DIGITS = 340;
5780 * When someone turns on scientific mode, we assume that more than this number of
5781 * digits is due to flipping from some other mode that didn't restrict the maximum,
5782 * and so we force 1 integer digit. We don't bother to track and see if someone is
5783 * using exponential notation with more than this number, it wouldn't make sense
5784 * anyway, and this is just to make sure that someone turning on scientific mode with
5785 * default settings doesn't end up with lots of zeroes.
5787 static final int MAX_SCIENTIFIC_INTEGER_DIGITS = 8;
5789 // Proclaim JDK 1.1 serial compatibility.
5790 private static final long serialVersionUID = 864413376551465018L;
5792 private ArrayList<FieldPosition> attributes = new ArrayList<FieldPosition>();
5794 // The following are used in currency format
5796 // -- triple currency sign char array
5797 // private static final char[] tripleCurrencySign = {0xA4, 0xA4, 0xA4};
5798 // -- triple currency sign string
5799 // private static final String tripleCurrencyStr = new String(tripleCurrencySign);
5801 // -- default currency plural pattern char array
5802 // private static final char[] defaultCurrencyPluralPatternChar =
5803 // {0, '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4};
5804 // -- default currency plural pattern string
5805 // private static final String defaultCurrencyPluralPattern =
5806 // new String(defaultCurrencyPluralPatternChar);
5808 // pattern used in this formatter
5809 private String formatPattern = "";
5810 // style is only valid when decimal formatter is constructed by
5811 // DecimalFormat(pattern, decimalFormatSymbol, style)
5812 private int style = NumberFormat.NUMBERSTYLE;
5814 * Represents whether this is a currency format, and which currency format style. 0:
5815 * not currency format type; 1: currency style -- symbol name, such as "$" for US
5816 * dollar. 2: currency style -- ISO name, such as USD for US dollar. 3: currency style
5817 * -- plural long name, such as "US Dollar" for "1.00 US Dollar", or "US Dollars" for
5818 * "3.00 US Dollars".
5820 private int currencySignCount = CURRENCY_SIGN_COUNT_ZERO;
5823 * For parsing purposes, we need to remember all prefix patterns and suffix patterns
5824 * of every currency format pattern, including the pattern of the default currency
5825 * style, ISO currency style, and plural currency style. The patterns are set through
5826 * applyPattern. The following are used to represent the affix patterns in currency
5829 private static final class AffixForCurrency {
5830 // negative prefix pattern
5831 private String negPrefixPatternForCurrency = null;
5832 // negative suffix pattern
5833 private String negSuffixPatternForCurrency = null;
5834 // positive prefix pattern
5835 private String posPrefixPatternForCurrency = null;
5836 // positive suffix pattern
5837 private String posSuffixPatternForCurrency = null;
5838 private final int patternType;
5840 public AffixForCurrency(String negPrefix, String negSuffix, String posPrefix,
5841 String posSuffix, int type) {
5842 negPrefixPatternForCurrency = negPrefix;
5843 negSuffixPatternForCurrency = negSuffix;
5844 posPrefixPatternForCurrency = posPrefix;
5845 posSuffixPatternForCurrency = posSuffix;
5849 public String getNegPrefix() {
5850 return negPrefixPatternForCurrency;
5853 public String getNegSuffix() {
5854 return negSuffixPatternForCurrency;
5857 public String getPosPrefix() {
5858 return posPrefixPatternForCurrency;
5861 public String getPosSuffix() {
5862 return posSuffixPatternForCurrency;
5865 public int getPatternType() {
5870 // Affix pattern set for currency. It is a set of AffixForCurrency, each element of
5871 // the set saves the negative prefix, negative suffix, positive prefix, and positive
5872 // suffix of a pattern.
5873 private transient Set<AffixForCurrency> affixPatternsForCurrency = null;
5875 // For currency parsing. Since currency parsing needs to parse against all currency
5876 // patterns, before the parsing, we need to set up the affix patterns for all currencies.
5877 private transient boolean isReadyForParsing = false;
5879 // Information needed for DecimalFormat to format/parse currency plural.
5880 private CurrencyPluralInfo currencyPluralInfo = null;
5883 * Unit is an immutable class for the textual representation of a unit, in
5884 * particular its prefix and suffix.
5890 private final String prefix;
5891 private final String suffix;
5893 public Unit(String prefix, String suffix) {
5894 this.prefix = prefix;
5895 this.suffix = suffix;
5898 public void writeSuffix(StringBuffer toAppendTo) {
5899 toAppendTo.append(suffix);
5902 public void writePrefix(StringBuffer toAppendTo) {
5903 toAppendTo.append(prefix);
5907 public boolean equals(Object obj) {
5911 if (!(obj instanceof Unit)) {
5914 Unit other = (Unit) obj;
5915 return prefix.equals(other.prefix) && suffix.equals(other.suffix);
5918 public String toString() {
5919 return prefix + "/" + suffix;
5923 static final Unit NULL_UNIT = new Unit("", "");
5925 // Note about rounding implementation
5927 // The original design intended to skip rounding operation when roundingIncrement is not
5928 // set. However, rounding may need to occur when fractional digits exceed the width of
5929 // fractional part of pattern.
5931 // DigitList class has built-in rounding mechanism, using ROUND_HALF_EVEN. This implementation
5932 // forces non-null roundingIncrement if the setting is other than ROUND_HALF_EVEN, otherwise,
5933 // when rounding occurs in DigitList by pattern's fractional digits' width, the result
5934 // does not match the rounding mode.
5936 // Ideally, all rounding operation should be done in one place like ICU4C trunk does
5937 // (ICU4C rounding implementation was rewritten recently). This is intrim implemetation
5938 // to fix various issues. In the future, we should entire implementation of rounding
5939 // in this class, like ICU4C did.
5941 // Once we fully implement rounding logic in DigitList, then following fields and methods
5944 private transient BigDecimal actualRoundingIncrementICU = null;
5945 private transient java.math.BigDecimal actualRoundingIncrement = null;
5948 * The actual rounding increment as a double.
5950 private transient double roundingDouble = 0.0;
5953 * If the roundingDouble is the reciprocal of an integer (the most common case!), this
5954 * is set to be that integer. Otherwise it is 0.0.
5956 private transient double roundingDoubleReciprocal = 0.0;
5959 * Set roundingDouble, roundingDoubleReciprocal and actualRoundingIncrement
5960 * based on rounding mode and width of fractional digits. Whenever setting affecting
5961 * rounding mode, rounding increment and maximum width of fractional digits, then
5962 * this method must be called.
5964 * roundingIncrementICU is the field storing the custom rounding increment value,
5965 * while actual rounding increment could be larger.
5967 private void resetActualRounding() {
5968 if (roundingIncrementICU != null) {
5969 BigDecimal byWidth = getMaximumFractionDigits() > 0 ?
5970 BigDecimal.ONE.movePointLeft(getMaximumFractionDigits()) : BigDecimal.ONE;
5971 if (roundingIncrementICU.compareTo(byWidth) >= 0) {
5972 actualRoundingIncrementICU = roundingIncrementICU;
5974 actualRoundingIncrementICU = byWidth.equals(BigDecimal.ONE) ? null : byWidth;
5977 if (roundingMode == BigDecimal.ROUND_HALF_EVEN) {
5978 actualRoundingIncrementICU = null;
5980 if (getMaximumFractionDigits() > 0) {
5981 actualRoundingIncrementICU = BigDecimal.ONE.movePointLeft(getMaximumFractionDigits());
5986 if (actualRoundingIncrementICU == null) {
5987 setRoundingDouble(0.0d);
5988 actualRoundingIncrement = null;
5990 setRoundingDouble(actualRoundingIncrementICU.doubleValue());
5991 actualRoundingIncrement = actualRoundingIncrementICU.toBigDecimal();
5995 static final double roundingIncrementEpsilon = 0.000000001;
5997 private void setRoundingDouble(double newValue) {
5998 roundingDouble = newValue;
5999 if (roundingDouble > 0.0d) {
6000 double rawRoundedReciprocal = 1.0d / roundingDouble;
6001 roundingDoubleReciprocal = Math.rint(rawRoundedReciprocal);
6002 if (Math.abs(rawRoundedReciprocal - roundingDoubleReciprocal) > roundingIncrementEpsilon) {
6003 roundingDoubleReciprocal = 0.0d;
6006 roundingDoubleReciprocal = 0.0d;