1/* GENERATED SOURCE. DO NOT MODIFY. */ 2// © 2016 and later: Unicode, Inc. and others. 3// License & terms of use: http://www.unicode.org/copyright.html#License 4/* 5 ******************************************************************************* 6 * Copyright (C) 1996-2016, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10package android.icu.text; 11 12import java.io.IOException; 13import java.io.ObjectInputStream; 14import java.io.ObjectOutputStream; 15import java.math.BigInteger; 16import java.text.AttributedCharacterIterator; 17import java.text.AttributedString; 18import java.text.ChoiceFormat; 19import java.text.FieldPosition; 20import java.text.Format; 21import java.text.ParsePosition; 22import java.util.ArrayList; 23import java.util.HashSet; 24import java.util.Iterator; 25import java.util.Set; 26 27import android.icu.impl.ICUConfig; 28import android.icu.impl.PatternProps; 29import android.icu.impl.Utility; 30import android.icu.lang.UCharacter; 31import android.icu.math.BigDecimal; 32import android.icu.math.MathContext; 33import android.icu.text.PluralRules.FixedDecimal; 34import android.icu.util.Currency; 35import android.icu.util.Currency.CurrencyUsage; 36import android.icu.util.CurrencyAmount; 37import android.icu.util.ULocale; 38import android.icu.util.ULocale.Category; 39 40/** 41 * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.text.DecimalFormat}. Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'. 42 * 43 * <code>DecimalFormat</code> is a concrete subclass of {@link NumberFormat} that formats 44 * decimal numbers. It has a variety of features designed to make it possible to parse and 45 * format numbers in any locale, including support for Western, Arabic, or Indic digits. 46 * It also supports different flavors of numbers, including integers ("123"), fixed-point 47 * numbers ("123.4"), scientific notation ("1.23E4"), percentages ("12%"), and currency 48 * amounts ("$123.00", "USD123.00", "123.00 US dollars"). All of these flavors can be 49 * easily localized. 50 * 51 * <p>To obtain a {@link NumberFormat} for a specific locale (including the default 52 * locale) call one of <code>NumberFormat</code>'s factory methods such as {@link 53 * NumberFormat#getInstance}. Do not call the <code>DecimalFormat</code> constructors 54 * directly, unless you know what you are doing, since the {@link NumberFormat} factory 55 * methods may return subclasses other than <code>DecimalFormat</code>. If you need to 56 * customize the format object, do something like this: 57 * 58 * <blockquote><pre> 59 * NumberFormat f = NumberFormat.getInstance(loc); 60 * if (f instanceof DecimalFormat) { 61 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true); 62 * }</pre></blockquote> 63 * 64 * <p><strong>Example Usage</strong> 65 * 66 * Print out a number using the localized number, currency, and percent 67 * format for each locale. 68 * 69 * <blockquote><pre> 70 * Locale[] locales = NumberFormat.getAvailableLocales(); 71 * double myNumber = -1234.56; 72 * NumberFormat format; 73 * for (int j=0; j<3; ++j) { 74 * System.out.println("FORMAT"); 75 * for (int i = 0; i < locales.length; ++i) { 76 * if (locales[i].getCountry().length() == 0) { 77 * // Skip language-only locales 78 * continue; 79 * } 80 * System.out.print(locales[i].getDisplayName()); 81 * switch (j) { 82 * case 0: 83 * format = NumberFormat.getInstance(locales[i]); break; 84 * case 1: 85 * format = NumberFormat.getCurrencyInstance(locales[i]); break; 86 * default: 87 * format = NumberFormat.getPercentInstance(locales[i]); break; 88 * } 89 * try { 90 * // Assume format is a DecimalFormat 91 * System.out.print(": " + ((DecimalFormat) format).toPattern() 92 * + " -> " + form.format(myNumber)); 93 * } catch (Exception e) {} 94 * try { 95 * System.out.println(" -> " + format.parse(form.format(myNumber))); 96 * } catch (ParseException e) {} 97 * } 98 * }</pre></blockquote> 99 * 100 * <p>Another example use getInstance(style).<br> 101 * Print out a number using the localized number, currency, percent, 102 * scientific, integer, iso currency, and plural currency format for each locale. 103 * 104 * <blockquote><pre> 105 * ULocale locale = new ULocale("en_US"); 106 * double myNumber = 1234.56; 107 * for (int j=NumberFormat.NUMBERSTYLE; j<=NumberFormat.PLURALCURRENCYSTYLE; ++j) { 108 * NumberFormat format = NumberFormat.getInstance(locale, j); 109 * try { 110 * // Assume format is a DecimalFormat 111 * System.out.print(": " + ((DecimalFormat) format).toPattern() 112 * + " -> " + form.format(myNumber)); 113 * } catch (Exception e) {} 114 * try { 115 * System.out.println(" -> " + format.parse(form.format(myNumber))); 116 * } catch (ParseException e) {} 117 * }</pre></blockquote> 118 * 119 * <h3>Patterns</h3> 120 * 121 * <p>A <code>DecimalFormat</code> consists of a <em>pattern</em> and a set of 122 * <em>symbols</em>. The pattern may be set directly using {@link #applyPattern}, or 123 * indirectly using other API methods which manipulate aspects of the pattern, such as the 124 * minimum number of integer digits. The symbols are stored in a {@link 125 * DecimalFormatSymbols} object. When using the {@link NumberFormat} factory methods, the 126 * pattern and symbols are read from ICU's locale data. 127 * 128 * <h4>Special Pattern Characters</h4> 129 * 130 * <p>Many characters in a pattern are taken literally; they are matched during parsing 131 * and output unchanged during formatting. Special characters, on the other hand, stand 132 * for other characters, strings, or classes of characters. For example, the '#' 133 * character is replaced by a localized digit. Often the replacement character is the 134 * same as the pattern character; in the U.S. locale, the ',' grouping character is 135 * replaced by ','. However, the replacement is still happening, and if the symbols are 136 * modified, the grouping character changes. Some special characters affect the behavior 137 * of the formatter by their presence; for example, if the percent character is seen, then 138 * the value is multiplied by 100 before being displayed. 139 * 140 * <p>To insert a special character in a pattern as a literal, that is, without any 141 * special meaning, the character must be quoted. There are some exceptions to this which 142 * are noted below. 143 * 144 * <p>The characters listed here are used in non-localized patterns. Localized patterns 145 * use the corresponding characters taken from this formatter's {@link 146 * DecimalFormatSymbols} object instead, and these characters lose their special status. 147 * Two exceptions are the currency sign and quote, which are not localized. 148 * 149 * <blockquote> 150 * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol, 151 * location, localized, and meaning."> 152 * <tr style="background-color: #ccccff"> 153 * <th align=left>Symbol 154 * <th align=left>Location 155 * <th align=left>Localized? 156 * <th align=left>Meaning 157 * <tr style="vertical-align: top;"> 158 * <td><code>0</code> 159 * <td>Number 160 * <td>Yes 161 * <td>Digit 162 * <tr style="vertical-align: top; background-color: #eeeeff;"> 163 * <td><code>1-9</code> 164 * <td>Number 165 * <td>Yes 166 * <td>'1' through '9' indicate rounding. 167 * <tr style="vertical-align: top;"> 168 * <td><code>@</code> 169 * <td>Number 170 * <td>No 171 * <td>Significant digit 172 * <tr style="vertical-align: top; background-color: #eeeeff;"> 173 * <td><code>#</code> 174 * <td>Number 175 * <td>Yes 176 * <td>Digit, zero shows as absent 177 * <tr style="vertical-align: top;"> 178 * <td><code>.</code> 179 * <td>Number 180 * <td>Yes 181 * <td>Decimal separator or monetary decimal separator 182 * <tr style="vertical-align: top; background-color: #eeeeff;"> 183 * <td><code>-</code> 184 * <td>Number 185 * <td>Yes 186 * <td>Minus sign 187 * <tr style="vertical-align: top;"> 188 * <td><code>,</code> 189 * <td>Number 190 * <td>Yes 191 * <td>Grouping separator 192 * <tr style="vertical-align: top; background-color: #eeeeff;"> 193 * <td><code>E</code> 194 * <td>Number 195 * <td>Yes 196 * <td>Separates mantissa and exponent in scientific notation. 197 * <em>Need not be quoted in prefix or suffix.</em> 198 * <tr style="vertical-align: top;"> 199 * <td><code>+</code> 200 * <td>Exponent 201 * <td>Yes 202 * <td>Prefix positive exponents with localized plus sign. 203 * <em>Need not be quoted in prefix or suffix.</em> 204 * <tr style="vertical-align: top; background-color: #eeeeff;"> 205 * <td><code>;</code> 206 * <td>Subpattern boundary 207 * <td>Yes 208 * <td>Separates positive and negative subpatterns 209 * <tr style="vertical-align: top;"> 210 * <td><code>%</code> 211 * <td>Prefix or suffix 212 * <td>Yes 213 * <td>Multiply by 100 and show as percentage 214 * <tr style="vertical-align: top; background-color: #eeeeff;"> 215 * <td><code>\u2030</code> 216 * <td>Prefix or suffix 217 * <td>Yes 218 * <td>Multiply by 1000 and show as per mille 219 * <tr style="vertical-align: top;"> 220 * <td><code>¤</code> (<code>\u00A4</code>) 221 * <td>Prefix or suffix 222 * <td>No 223 * <td>Currency sign, replaced by currency symbol. If 224 * doubled, replaced by international currency symbol. 225 * If tripled, replaced by currency plural names, for example, 226 * "US dollar" or "US dollars" for America. 227 * If present in a pattern, the monetary decimal separator 228 * is used instead of the decimal separator. 229 * <tr style="vertical-align: top; background-color: #eeeeff;"> 230 * <td><code>'</code> 231 * <td>Prefix or suffix 232 * <td>No 233 * <td>Used to quote special characters in a prefix or suffix, 234 * for example, <code>"'#'#"</code> formats 123 to 235 * <code>"#123"</code>. To create a single quote 236 * itself, use two in a row: <code>"# o''clock"</code>. 237 * <tr style="vertical-align: top;"> 238 * <td><code>*</code> 239 * <td>Prefix or suffix boundary 240 * <td>Yes 241 * <td>Pad escape, precedes pad character 242 * </table> 243 * </blockquote> 244 * 245 * <p>A <code>DecimalFormat</code> pattern contains a postive and negative subpattern, for 246 * example, "#,##0.00;(#,##0.00)". Each subpattern has a prefix, a numeric part, and a 247 * suffix. If there is no explicit negative subpattern, the negative subpattern is the 248 * localized minus sign prefixed to the positive subpattern. That is, "0.00" alone is 249 * equivalent to "0.00;-0.00". If there is an explicit negative subpattern, it serves 250 * only to specify the negative prefix and suffix; the number of digits, minimal digits, 251 * and other characteristics are ignored in the negative subpattern. That means that 252 * "#,##0.0#;(#)" has precisely the same result as "#,##0.0#;(#,##0.0#)". 253 * 254 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, thousands 255 * separators, decimal separators, etc. may be set to arbitrary values, and they will 256 * appear properly during formatting. However, care must be taken that the symbols and 257 * strings do not conflict, or parsing will be unreliable. For example, either the 258 * positive and negative prefixes or the suffixes must be distinct for {@link #parse} to 259 * be able to distinguish positive from negative values. Another example is that the 260 * decimal separator and thousands separator should be distinct characters, or parsing 261 * will be impossible. 262 * 263 * <p>The <em>grouping separator</em> is a character that separates clusters of integer 264 * digits to make large numbers more legible. It commonly used for thousands, but in some 265 * locales it separates ten-thousands. The <em>grouping size</em> is the number of digits 266 * between the grouping separators, such as 3 for "100,000,000" or 4 for "1 0000 267 * 0000". There are actually two different grouping sizes: One used for the least 268 * significant integer digits, the <em>primary grouping size</em>, and one used for all 269 * others, the <em>secondary grouping size</em>. In most locales these are the same, but 270 * sometimes they are different. For example, if the primary grouping interval is 3, and 271 * the secondary is 2, then this corresponds to the pattern "#,##,##0", and the number 272 * 123456789 is formatted as "12,34,56,789". If a pattern contains multiple grouping 273 * separators, the interval between the last one and the end of the integer defines the 274 * primary grouping size, and the interval between the last two defines the secondary 275 * grouping size. All others are ignored, so "#,##,###,####" == "###,###,####" == 276 * "##,#,###,####". 277 * 278 * <p>Illegal patterns, such as "#.#.#" or "#.###,###", will cause 279 * <code>DecimalFormat</code> to throw an {@link IllegalArgumentException} with a message 280 * that describes the problem. 281 * 282 * <h4>Pattern BNF</h4> 283 * 284 * <pre> 285 * pattern := subpattern (';' subpattern)? 286 * subpattern := prefix? number exponent? suffix? 287 * number := (integer ('.' fraction)?) | sigDigits 288 * prefix := '\u0000'..'\uFFFD' - specialCharacters 289 * suffix := '\u0000'..'\uFFFD' - specialCharacters 290 * integer := '#'* '0'* '0' 291 * fraction := '0'* '#'* 292 * sigDigits := '#'* '@' '@'* '#'* 293 * exponent := 'E' '+'? '0'* '0' 294 * padSpec := '*' padChar 295 * padChar := '\u0000'..'\uFFFD' - quote 296 *   297 * Notation: 298 * X* 0 or more instances of X 299 * X? 0 or 1 instances of X 300 * X|Y either X or Y 301 * C..D any character from C up to D, inclusive 302 * S-T characters in S, except those in T 303 * </pre> 304 * The first subpattern is for positive numbers. The second (optional) 305 * subpattern is for negative numbers. 306 * 307 * <p>Not indicated in the BNF syntax above: 308 * 309 * <ul> 310 * 311 * <li>The grouping separator ',' can occur inside the integer and sigDigits 312 * elements, between any two pattern characters of that element, as long as the integer or 313 * sigDigits element is not followed by the exponent element. 314 * 315 * <li>Two grouping intervals are recognized: That between the decimal point and the first 316 * grouping symbol, and that between the first and second grouping symbols. These 317 * intervals are identical in most locales, but in some locales they differ. For example, 318 * the pattern "#,##,###" formats the number 123456789 as 319 * "12,34,56,789". 320 * 321 * <li>The pad specifier <code>padSpec</code> may appear before the prefix, after the 322 * prefix, before the suffix, after the suffix, or not at all. 323 * 324 * <li>In place of '0', the digits '1' through '9' may be used to indicate a rounding 325 * increment. 326 * 327 * </ul> 328 * 329 * <h4>Parsing</h4> 330 * 331 * <p><code>DecimalFormat</code> parses all Unicode characters that represent decimal 332 * digits, as defined by {@link UCharacter#digit}. In addition, 333 * <code>DecimalFormat</code> also recognizes as digits the ten consecutive characters 334 * starting with the localized zero digit defined in the {@link DecimalFormatSymbols} 335 * object. During formatting, the {@link DecimalFormatSymbols}-based digits are output. 336 * 337 * <p>During parsing, grouping separators are ignored. 338 * 339 * <p>For currency parsing, the formatter is able to parse every currency style formats no 340 * matter which style the formatter is constructed with. For example, a formatter 341 * instance gotten from NumberFormat.getInstance(ULocale, NumberFormat.CURRENCYSTYLE) can 342 * parse formats such as "USD1.00" and "3.00 US dollars". 343 * 344 * <p>If {@link #parse(String, ParsePosition)} fails to parse a string, it returns 345 * <code>null</code> and leaves the parse position unchanged. The convenience method 346 * {@link #parse(String)} indicates parse failure by throwing a {@link 347 * java.text.ParseException}. 348 * 349 * <p>Parsing an extremely large or small absolute value (such as 1.0E10000 or 1.0E-10000) 350 * requires huge memory allocation for representing the parsed number. Such input may expose 351 * a risk of DoS attacks. To prevent huge memory allocation triggered by such inputs, 352 * <code>DecimalFormat</code> internally limits of maximum decimal digits to be 1000. Thus, 353 * an input string resulting more than 1000 digits in plain decimal representation (non-exponent) 354 * will be treated as either overflow (positive/negative infinite) or underflow (+0.0/-0.0). 355 * 356 * <h4>Formatting</h4> 357 * 358 * <p>Formatting is guided by several parameters, all of which can be specified either 359 * using a pattern or using the API. The following description applies to formats that do 360 * not use <a href="#sci">scientific notation</a> or <a href="#sigdig">significant 361 * digits</a>. 362 * 363 * <ul><li>If the number of actual integer digits exceeds the <em>maximum integer 364 * digits</em>, then only the least significant digits are shown. For example, 1997 is 365 * formatted as "97" if the maximum integer digits is set to 2. 366 * 367 * <li>If the number of actual integer digits is less than the <em>minimum integer 368 * digits</em>, then leading zeros are added. For example, 1997 is formatted as "01997" 369 * if the minimum integer digits is set to 5. 370 * 371 * <li>If the number of actual fraction digits exceeds the <em>maximum fraction 372 * digits</em>, then half-even rounding it performed to the maximum fraction digits. For 373 * example, 0.125 is formatted as "0.12" if the maximum fraction digits is 2. This 374 * behavior can be changed by specifying a rounding increment and a rounding mode. 375 * 376 * <li>If the number of actual fraction digits is less than the <em>minimum fraction 377 * digits</em>, then trailing zeros are added. For example, 0.125 is formatted as 378 * "0.1250" if the mimimum fraction digits is set to 4. 379 * 380 * <li>Trailing fractional zeros are not displayed if they occur <em>j</em> positions 381 * after the decimal, where <em>j</em> is less than the maximum fraction digits. For 382 * example, 0.10004 is formatted as "0.1" if the maximum fraction digits is four or less. 383 * </ul> 384 * 385 * <p><strong>Special Values</strong> 386 * 387 * <p><code>NaN</code> is represented as a single character, typically 388 * <code>\uFFFD</code>. This character is determined by the {@link 389 * DecimalFormatSymbols} object. This is the only value for which the prefixes and 390 * suffixes are not used. 391 * 392 * <p>Infinity is represented as a single character, typically <code>\u221E</code>, 393 * with the positive or negative prefixes and suffixes applied. The infinity character is 394 * determined by the {@link DecimalFormatSymbols} object. 395 * 396 * <h4><a name="sci">Scientific Notation</a></h4> 397 * 398 * <p>Numbers in scientific notation are expressed as the product of a mantissa and a 399 * power of ten, for example, 1234 can be expressed as 1.234 x 10<sup>3</sup>. The 400 * mantissa is typically in the half-open interval [1.0, 10.0) or sometimes [0.0, 1.0), 401 * but it need not be. <code>DecimalFormat</code> supports arbitrary mantissas. 402 * <code>DecimalFormat</code> can be instructed to use scientific notation through the API 403 * or through the pattern. In a pattern, the exponent character immediately followed by 404 * one or more digit characters indicates scientific notation. Example: "0.###E0" formats 405 * the number 1234 as "1.234E3". 406 * 407 * <ul> 408 * 409 * <li>The number of digit characters after the exponent character gives the minimum 410 * exponent digit count. There is no maximum. Negative exponents are formatted using the 411 * localized minus sign, <em>not</em> the prefix and suffix from the pattern. This allows 412 * patterns such as "0.###E0 m/s". To prefix positive exponents with a localized plus 413 * sign, specify '+' between the exponent and the digits: "0.###E+0" will produce formats 414 * "1E+1", "1E+0", "1E-1", etc. (In localized patterns, use the localized plus sign 415 * rather than '+'.) 416 * 417 * <li>The minimum number of integer digits is achieved by adjusting the exponent. 418 * Example: 0.00123 formatted with "00.###E0" yields "12.3E-4". This only happens if 419 * there is no maximum number of integer digits. If there is a maximum, then the minimum 420 * number of integer digits is fixed at one. 421 * 422 * <li>The maximum number of integer digits, if present, specifies the exponent grouping. 423 * The most common use of this is to generate <em>engineering notation</em>, in which the 424 * exponent is a multiple of three, e.g., "##0.###E0". The number 12345 is formatted 425 * using "##0.####E0" as "12.345E3". 426 * 427 * <li>When using scientific notation, the formatter controls the digit counts using 428 * significant digits logic. The maximum number of significant digits limits the total 429 * number of integer and fraction digits that will be shown in the mantissa; it does not 430 * affect parsing. For example, 12345 formatted with "##0.##E0" is "12.3E3". See the 431 * section on significant digits for more details. 432 * 433 * <li>The number of significant digits shown is determined as follows: If 434 * areSignificantDigitsUsed() returns false, then the minimum number of significant digits 435 * shown is one, and the maximum number of significant digits shown is the sum of the 436 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is unaffected by the 437 * maximum integer digits. If this sum is zero, then all significant digits are shown. 438 * If areSignificantDigitsUsed() returns true, then the significant digit counts are 439 * specified by getMinimumSignificantDigits() and getMaximumSignificantDigits(). In this 440 * case, the number of integer digits is fixed at one, and there is no exponent grouping. 441 * 442 * <li>Exponential patterns may not contain grouping separators. 443 * 444 * </ul> 445 * 446 * <h4><a name="sigdig">Significant Digits</a></h4> 447 * 448 * <code>DecimalFormat</code> has two ways of controlling how many digits are shows: (a) 449 * significant digits counts, or (b) integer and fraction digit counts. Integer and 450 * fraction digit counts are described above. When a formatter is using significant 451 * digits counts, the number of integer and fraction digits is not specified directly, and 452 * the formatter settings for these counts are ignored. Instead, the formatter uses 453 * however many integer and fraction digits are required to display the specified number 454 * of significant digits. Examples: 455 * 456 * <blockquote> 457 * <table border=0 cellspacing=3 cellpadding=0> 458 * <tr style="background-color: #ccccff"> 459 * <th align=left>Pattern 460 * <th align=left>Minimum significant digits 461 * <th align=left>Maximum significant digits 462 * <th align=left>Number 463 * <th align=left>Output of format() 464 * <tr style="vertical-align: top;"> 465 * <td><code>@@@</code> 466 * <td>3 467 * <td>3 468 * <td>12345 469 * <td><code>12300</code> 470 * <tr style="vertical-align: top; background-color: #eeeeff;"> 471 * <td><code>@@@</code> 472 * <td>3 473 * <td>3 474 * <td>0.12345 475 * <td><code>0.123</code> 476 * <tr style="vertical-align: top;"> 477 * <td><code>@@##</code> 478 * <td>2 479 * <td>4 480 * <td>3.14159 481 * <td><code>3.142</code> 482 * <tr style="vertical-align: top; background-color: #eeeeff;"> 483 * <td><code>@@##</code> 484 * <td>2 485 * <td>4 486 * <td>1.23004 487 * <td><code>1.23</code> 488 * </table> 489 * </blockquote> 490 * 491 * <ul> 492 * 493 * <li>Significant digit counts may be expressed using patterns that specify a minimum and 494 * maximum number of significant digits. These are indicated by the <code>'@'</code> and 495 * <code>'#'</code> characters. The minimum number of significant digits is the number of 496 * <code>'@'</code> characters. The maximum number of significant digits is the number of 497 * <code>'@'</code> characters plus the number of <code>'#'</code> characters following on 498 * the right. For example, the pattern <code>"@@@"</code> indicates exactly 3 significant 499 * digits. The pattern <code>"@##"</code> indicates from 1 to 3 significant digits. 500 * Trailing zero digits to the right of the decimal separator are suppressed after the 501 * minimum number of significant digits have been shown. For example, the pattern 502 * <code>"@##"</code> formats the number 0.1203 as <code>"0.12"</code>. 503 * 504 * <li>If a pattern uses significant digits, it may not contain a decimal separator, nor 505 * the <code>'0'</code> pattern character. Patterns such as <code>"@00"</code> or 506 * <code>"@.###"</code> are disallowed. 507 * 508 * <li>Any number of <code>'#'</code> characters may be prepended to the left of the 509 * leftmost <code>'@'</code> character. These have no effect on the minimum and maximum 510 * significant digits counts, but may be used to position grouping separators. For 511 * example, <code>"#,#@#"</code> indicates a minimum of one significant digits, a maximum 512 * of two significant digits, and a grouping size of three. 513 * 514 * <li>In order to enable significant digits formatting, use a pattern containing the 515 * <code>'@'</code> pattern character. Alternatively, call {@link 516 * #setSignificantDigitsUsed setSignificantDigitsUsed(true)}. 517 * 518 * <li>In order to disable significant digits formatting, use a pattern that does not 519 * contain the <code>'@'</code> pattern character. Alternatively, call {@link 520 * #setSignificantDigitsUsed setSignificantDigitsUsed(false)}. 521 * 522 * <li>The number of significant digits has no effect on parsing. 523 * 524 * <li>Significant digits may be used together with exponential notation. Such patterns 525 * are equivalent to a normal exponential pattern with a minimum and maximum integer digit 526 * count of one, a minimum fraction digit count of <code>getMinimumSignificantDigits() - 527 * 1</code>, and a maximum fraction digit count of <code>getMaximumSignificantDigits() - 528 * 1</code>. For example, the pattern <code>"@@###E0"</code> is equivalent to 529 * <code>"0.0###E0"</code>. 530 * 531 * <li>If signficant digits are in use, then the integer and fraction digit counts, as set 532 * via the API, are ignored. If significant digits are not in use, then the signficant 533 * digit counts, as set via the API, are ignored. 534 * 535 * </ul> 536 * 537 * <h4>Padding</h4> 538 * 539 * <p><code>DecimalFormat</code> supports padding the result of {@link #format} to a 540 * specific width. Padding may be specified either through the API or through the pattern 541 * syntax. In a pattern the pad escape character, followed by a single pad character, 542 * causes padding to be parsed and formatted. The pad escape character is '*' in 543 * unlocalized patterns, and can be localized using {@link 544 * DecimalFormatSymbols#setPadEscape}. For example, <code>"$*x#,##0.00"</code> formats 545 * 123 to <code>"$xx123.00"</code>, and 1234 to <code>"$1,234.00"</code>. 546 * 547 * <ul> 548 * 549 * <li>When padding is in effect, the width of the positive subpattern, including prefix 550 * and suffix, determines the format width. For example, in the pattern <code>"* #0 551 * o''clock"</code>, the format width is 10. 552 * 553 * <li>The width is counted in 16-bit code units (Java <code>char</code>s). 554 * 555 * <li>Some parameters which usually do not matter have meaning when padding is used, 556 * because the pattern width is significant with padding. In the pattern "* 557 * ##,##,#,##0.##", the format width is 14. The initial characters "##,##," do not affect 558 * the grouping size or maximum integer digits, but they do affect the format width. 559 * 560 * <li>Padding may be inserted at one of four locations: before the prefix, after the 561 * prefix, before the suffix, or after the suffix. If padding is specified in any other 562 * location, {@link #applyPattern} throws an {@link IllegalArgumentException}. If there 563 * is no prefix, before the prefix and after the prefix are equivalent, likewise for the 564 * suffix. 565 * 566 * <li>When specified in a pattern, the 16-bit <code>char</code> immediately following the 567 * pad escape is the pad character. This may be any character, including a special pattern 568 * character. That is, the pad escape <em>escapes</em> the following character. If there 569 * is no character after the pad escape, then the pattern is illegal. 570 * 571 * </ul> 572 * 573 * <p> 574 * <strong>Rounding</strong> 575 * 576 * <p><code>DecimalFormat</code> supports rounding to a specific increment. For example, 577 * 1230 rounded to the nearest 50 is 1250. 1.234 rounded to the nearest 0.65 is 1.3. The 578 * rounding increment may be specified through the API or in a pattern. To specify a 579 * rounding increment in a pattern, include the increment in the pattern itself. "#,#50" 580 * specifies a rounding increment of 50. "#,##0.05" specifies a rounding increment of 581 * 0.05. 582 * 583 * <ul> 584 * 585 * <li>Rounding only affects the string produced by formatting. It does not affect 586 * parsing or change any numerical values. 587 * 588 * <li>A <em>rounding mode</em> determines how values are rounded; see the {@link 589 * android.icu.math.BigDecimal} documentation for a description of the modes. Rounding 590 * increments specified in patterns use the default mode, {@link 591 * android.icu.math.BigDecimal#ROUND_HALF_EVEN}. 592 * 593 * <li>Some locales use rounding in their currency formats to reflect the smallest 594 * currency denomination. 595 * 596 * <li>In a pattern, digits '1' through '9' specify rounding, but otherwise behave 597 * identically to digit '0'. 598 * 599 * </ul> 600 * 601 * <h4>Synchronization</h4> 602 * 603 * <p><code>DecimalFormat</code> objects are not synchronized. Multiple threads should 604 * not access one formatter concurrently. 605 * 606 * @see java.text.Format 607 * @see NumberFormat 608 * @author Mark Davis 609 * @author Alan Liu 610 */ 611public class DecimalFormat extends NumberFormat { 612 613 /** 614 * Creates a DecimalFormat using the default pattern and symbols for the default 615 * <code>FORMAT</code> locale. This is a convenient way to obtain a DecimalFormat when 616 * internationalization is not the main concern. 617 * 618 * <p>To obtain standard formats for a given locale, use the factory methods on 619 * NumberFormat such as getNumberInstance. These factories will return the most 620 * appropriate sub-class of NumberFormat for a given locale. 621 * 622 * @see NumberFormat#getInstance 623 * @see NumberFormat#getNumberInstance 624 * @see NumberFormat#getCurrencyInstance 625 * @see NumberFormat#getPercentInstance 626 * @see Category#FORMAT 627 */ 628 public DecimalFormat() { 629 ULocale def = ULocale.getDefault(Category.FORMAT); 630 String pattern = getPattern(def, 0); 631 // Always applyPattern after the symbols are set 632 this.symbols = new DecimalFormatSymbols(def); 633 setCurrency(Currency.getInstance(def)); 634 applyPatternWithoutExpandAffix(pattern, false); 635 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 636 currencyPluralInfo = new CurrencyPluralInfo(def); 637 // the exact pattern is not known until the plural count is known. 638 // so, no need to expand affix now. 639 } else { 640 expandAffixAdjustWidth(null); 641 } 642 } 643 644 /** 645 * Creates a DecimalFormat from the given pattern and the symbols for the default 646 * <code>FORMAT</code> locale. This is a convenient way to obtain a DecimalFormat when 647 * internationalization is not the main concern. 648 * 649 * <p>To obtain standard formats for a given locale, use the factory methods on 650 * NumberFormat such as getNumberInstance. These factories will return the most 651 * appropriate sub-class of NumberFormat for a given locale. 652 * 653 * @param pattern A non-localized pattern string. 654 * @throws IllegalArgumentException if the given pattern is invalid. 655 * @see NumberFormat#getInstance 656 * @see NumberFormat#getNumberInstance 657 * @see NumberFormat#getCurrencyInstance 658 * @see NumberFormat#getPercentInstance 659 * @see Category#FORMAT 660 */ 661 public DecimalFormat(String pattern) { 662 // Always applyPattern after the symbols are set 663 ULocale def = ULocale.getDefault(Category.FORMAT); 664 this.symbols = new DecimalFormatSymbols(def); 665 setCurrency(Currency.getInstance(def)); 666 applyPatternWithoutExpandAffix(pattern, false); 667 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 668 currencyPluralInfo = new CurrencyPluralInfo(def); 669 } else { 670 expandAffixAdjustWidth(null); 671 } 672 } 673 674 /** 675 * Creates a DecimalFormat from the given pattern and symbols. Use this constructor 676 * when you need to completely customize the behavior of the format. 677 * 678 * <p>To obtain standard formats for a given locale, use the factory methods on 679 * NumberFormat such as getInstance or getCurrencyInstance. If you need only minor 680 * adjustments to a standard format, you can modify the format returned by a 681 * NumberFormat factory method. 682 * 683 * @param pattern a non-localized pattern string 684 * @param symbols the set of symbols to be used 685 * @exception IllegalArgumentException if the given pattern is invalid 686 * @see NumberFormat#getInstance 687 * @see NumberFormat#getNumberInstance 688 * @see NumberFormat#getCurrencyInstance 689 * @see NumberFormat#getPercentInstance 690 * @see DecimalFormatSymbols 691 */ 692 public DecimalFormat(String pattern, DecimalFormatSymbols symbols) { 693 createFromPatternAndSymbols(pattern, symbols); 694 } 695 696 private void createFromPatternAndSymbols(String pattern, DecimalFormatSymbols inputSymbols) { 697 // Always applyPattern after the symbols are set 698 symbols = (DecimalFormatSymbols) inputSymbols.clone(); 699 if (pattern.indexOf(CURRENCY_SIGN) >= 0) { 700 // Only spend time with currency symbols when we're going to display it. 701 // Also set some defaults before the apply pattern. 702 setCurrencyForSymbols(); 703 } 704 applyPatternWithoutExpandAffix(pattern, false); 705 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 706 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale()); 707 } else { 708 expandAffixAdjustWidth(null); 709 } 710 } 711 712 /** 713 * Creates a DecimalFormat from the given pattern, symbols, information used for 714 * currency plural format, and format style. Use this constructor when you need to 715 * completely customize the behavior of the format. 716 * 717 * <p>To obtain standard formats for a given locale, use the factory methods on 718 * NumberFormat such as getInstance or getCurrencyInstance. 719 * 720 * <p>If you need only minor adjustments to a standard format, you can modify the 721 * format returned by a NumberFormat factory method using the setters. 722 * 723 * <p>If you want to completely customize a decimal format, using your own 724 * DecimalFormatSymbols (such as group separators) and your own information for 725 * currency plural formatting (such as plural rule and currency plural patterns), you 726 * can use this constructor. 727 * 728 * @param pattern a non-localized pattern string 729 * @param symbols the set of symbols to be used 730 * @param infoInput the information used for currency plural format, including 731 * currency plural patterns and plural rules. 732 * @param style the decimal formatting style, it is one of the following values: 733 * NumberFormat.NUMBERSTYLE; NumberFormat.CURRENCYSTYLE; NumberFormat.PERCENTSTYLE; 734 * NumberFormat.SCIENTIFICSTYLE; NumberFormat.INTEGERSTYLE; 735 * NumberFormat.ISOCURRENCYSTYLE; NumberFormat.PLURALCURRENCYSTYLE; 736 */ 737 public DecimalFormat(String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput, 738 int style) { 739 CurrencyPluralInfo info = infoInput; 740 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 741 info = (CurrencyPluralInfo) infoInput.clone(); 742 } 743 create(pattern, symbols, info, style); 744 } 745 746 private void create(String pattern, DecimalFormatSymbols inputSymbols, CurrencyPluralInfo info, 747 int inputStyle) { 748 if (inputStyle != NumberFormat.PLURALCURRENCYSTYLE) { 749 createFromPatternAndSymbols(pattern, inputSymbols); 750 } else { 751 // Always applyPattern after the symbols are set 752 symbols = (DecimalFormatSymbols) inputSymbols.clone(); 753 currencyPluralInfo = info; 754 // the pattern used in format is not fixed until formatting, in which, the 755 // number is known and will be used to pick the right pattern based on plural 756 // count. Here, set the pattern as the pattern of plural count == "other". 757 // For most locale, the patterns are probably the same for all plural 758 // count. If not, the right pattern need to be re-applied during format. 759 String currencyPluralPatternForOther = 760 currencyPluralInfo.getCurrencyPluralPattern("other"); 761 applyPatternWithoutExpandAffix(currencyPluralPatternForOther, false); 762 setCurrencyForSymbols(); 763 } 764 style = inputStyle; 765 } 766 767 /** 768 * Creates a DecimalFormat for currency plural format from the given pattern, symbols, 769 * and style. 770 */ 771 DecimalFormat(String pattern, DecimalFormatSymbols inputSymbols, int style) { 772 CurrencyPluralInfo info = null; 773 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 774 info = new CurrencyPluralInfo(inputSymbols.getULocale()); 775 } 776 create(pattern, inputSymbols, info, style); 777 } 778 779 /** 780 * {@inheritDoc} 781 */ 782 @Override 783 public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) { 784 return format(number, result, fieldPosition, false); 785 } 786 787 // See if number is negative. 788 // usage: isNegative(multiply(numberToBeFormatted)); 789 private boolean isNegative(double number) { 790 // Detecting whether a double is negative is easy with the exception of the value 791 // -0.0. This is a double which has a zero mantissa (and exponent), but a negative 792 // sign bit. It is semantically distinct from a zero with a positive sign bit, and 793 // this distinction is important to certain kinds of computations. However, it's a 794 // little tricky to detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you 795 // may ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == 796 // -Infinity. Proper detection of -0.0 is needed to deal with the issues raised by 797 // bugs 4106658, 4106667, and 4147706. Liu 7/6/98. 798 return (number < 0.0) || (number == 0.0 && 1 / number < 0.0); 799 } 800 801 // Rounds the number and strips of the negative sign. 802 // usage: round(multiply(numberToBeFormatted)) 803 private double round(double number) { 804 boolean isNegative = isNegative(number); 805 if (isNegative) 806 number = -number; 807 808 // Apply rounding after multiplier 809 if (roundingDouble > 0.0) { 810 // number = roundingDouble 811 // * round(number / roundingDouble, roundingMode, isNegative); 812 return round( 813 number, roundingDouble, roundingDoubleReciprocal, roundingMode, 814 isNegative); 815 } 816 return number; 817 } 818 819 // Multiplies given number by multipler (if there is one) returning the new 820 // number. If there is no multiplier, returns the number passed in unchanged. 821 private double multiply(double number) { 822 if (multiplier != 1) { 823 return number * multiplier; 824 } 825 return number; 826 } 827 828 // [Spark/CDL] The actual method to format number. If boolean value 829 // parseAttr == true, then attribute information will be recorded. 830 private StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition, 831 boolean parseAttr) { 832 fieldPosition.setBeginIndex(0); 833 fieldPosition.setEndIndex(0); 834 835 if (Double.isNaN(number)) { 836 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 837 fieldPosition.setBeginIndex(result.length()); 838 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 839 fieldPosition.setBeginIndex(result.length()); 840 } 841 842 result.append(symbols.getNaN()); 843 // TODO: Combine setting a single FieldPosition or adding to an AttributedCharacterIterator 844 // into a function like recordAttribute(FieldAttribute, begin, end). 845 846 // [Spark/CDL] Add attribute for NaN here. 847 // result.append(symbols.getNaN()); 848 if (parseAttr) { 849 addAttribute(Field.INTEGER, result.length() - symbols.getNaN().length(), 850 result.length()); 851 } 852 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 853 fieldPosition.setEndIndex(result.length()); 854 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 855 fieldPosition.setEndIndex(result.length()); 856 } 857 858 addPadding(result, fieldPosition, 0, 0); 859 return result; 860 } 861 862 // Do this BEFORE checking to see if value is negative or infinite and 863 // before rounding. 864 number = multiply(number); 865 boolean isNegative = isNegative(number); 866 number = round(number); 867 868 if (Double.isInfinite(number)) { 869 int prefixLen = appendAffix(result, isNegative, true, fieldPosition, parseAttr); 870 871 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 872 fieldPosition.setBeginIndex(result.length()); 873 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 874 fieldPosition.setBeginIndex(result.length()); 875 } 876 877 // [Spark/CDL] Add attribute for infinity here. 878 result.append(symbols.getInfinity()); 879 if (parseAttr) { 880 addAttribute(Field.INTEGER, result.length() - symbols.getInfinity().length(), 881 result.length()); 882 } 883 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 884 fieldPosition.setEndIndex(result.length()); 885 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 886 fieldPosition.setEndIndex(result.length()); 887 } 888 889 int suffixLen = appendAffix(result, isNegative, false, fieldPosition, parseAttr); 890 891 addPadding(result, fieldPosition, prefixLen, suffixLen); 892 return result; 893 } 894 895 int precision = precision(false); 896 897 // This is to fix rounding for scientific notation. See ticket:10542. 898 // This code should go away when a permanent fix is done for ticket:9931. 899 // 900 // This block of code only executes for scientific notation so it will not interfere with the 901 // previous fix in {@link #resetActualRounding} for fixed decimal numbers. 902 // Moreover this code only runs when there is rounding to be done (precision > 0) and when the 903 // rounding mode is something other than ROUND_HALF_EVEN. 904 // This block of code does the correct rounding of number in advance so that it will fit into 905 // the number of digits indicated by precision. In this way, we avoid using the default 906 // ROUND_HALF_EVEN behavior of DigitList. For example, if number = 0.003016 and roundingMode = 907 // ROUND_DOWN and precision = 3 then after this code executes, number = 0.00301 (3 significant digits) 908 if (useExponentialNotation && precision > 0 && number != 0.0 && roundingMode != BigDecimal.ROUND_HALF_EVEN) { 909 int log10RoundingIncr = 1 - precision + (int) Math.floor(Math.log10(Math.abs(number))); 910 double roundingIncReciprocal = 0.0; 911 double roundingInc = 0.0; 912 if (log10RoundingIncr < 0) { 913 roundingIncReciprocal = 914 BigDecimal.ONE.movePointRight(-log10RoundingIncr).doubleValue(); 915 } else { 916 roundingInc = 917 BigDecimal.ONE.movePointRight(log10RoundingIncr).doubleValue(); 918 } 919 number = DecimalFormat.round(number, roundingInc, roundingIncReciprocal, roundingMode, isNegative); 920 } 921 // End fix for ticket:10542 922 923 // At this point we are guaranteed a nonnegative finite 924 // number. 925 synchronized (digitList) { 926 digitList.set(number, precision, !useExponentialNotation && 927 !areSignificantDigitsUsed()); 928 return subformat(number, result, fieldPosition, isNegative, false, parseAttr); 929 } 930 } 931 932 /** 933 * This is a special function used by the CompactDecimalFormat subclass. 934 * It completes only the rounding portion of the formatting and returns 935 * the resulting double. CompactDecimalFormat uses the result to compute 936 * the plural form to use. 937 * 938 * @param number The number to format. 939 * @return The number rounded to the correct number of significant digits 940 * with negative sign stripped off. 941 * @deprecated This API is ICU internal only. 942 * @hide draft / provisional / internal are hidden on Android 943 */ 944 @Deprecated 945 double adjustNumberAsInFormatting(double number) { 946 if (Double.isNaN(number)) { 947 return number; 948 } 949 number = round(multiply(number)); 950 if (Double.isInfinite(number)) { 951 return number; 952 } 953 return toDigitList(number).getDouble(); 954 } 955 956 @Deprecated 957 DigitList toDigitList(double number) { 958 DigitList result = new DigitList(); 959 result.set(number, precision(false), false); 960 return result; 961 } 962 963 /** 964 * This is a special function used by the CompactDecimalFormat subclass 965 * to determine if the number to be formatted is negative. 966 * 967 * @param number The number to format. 968 * @return True if number is negative. 969 * @deprecated This API is ICU internal only. 970 * @hide draft / provisional / internal are hidden on Android 971 */ 972 @Deprecated 973 boolean isNumberNegative(double number) { 974 if (Double.isNaN(number)) { 975 return false; 976 } 977 return isNegative(multiply(number)); 978 } 979 980 /** 981 * Round a double value to the nearest multiple of the given rounding increment, 982 * according to the given mode. This is equivalent to rounding value/roundingInc to 983 * the nearest integer, according to the given mode, and returning that integer * 984 * roundingInc. Note this is changed from the version in 2.4, since division of 985 * doubles have inaccuracies. jitterbug 1871. 986 * 987 * @param number 988 * the absolute value of the number to be rounded 989 * @param roundingInc 990 * the rounding increment 991 * @param roundingIncReciprocal 992 * if non-zero, is the reciprocal of rounding inc. 993 * @param mode 994 * a BigDecimal rounding mode 995 * @param isNegative 996 * true if the number to be rounded is negative 997 * @return the absolute value of the rounded result 998 */ 999 private static double round(double number, double roundingInc, double roundingIncReciprocal, 1000 int mode, boolean isNegative) { 1001 1002 double div = roundingIncReciprocal == 0.0 ? number / roundingInc : number * 1003 roundingIncReciprocal; 1004 1005 // do the absolute cases first 1006 1007 switch (mode) { 1008 case BigDecimal.ROUND_CEILING: 1009 div = (isNegative ? Math.floor(div + epsilon) : Math.ceil(div - epsilon)); 1010 break; 1011 case BigDecimal.ROUND_FLOOR: 1012 div = (isNegative ? Math.ceil(div - epsilon) : Math.floor(div + epsilon)); 1013 break; 1014 case BigDecimal.ROUND_DOWN: 1015 div = (Math.floor(div + epsilon)); 1016 break; 1017 case BigDecimal.ROUND_UP: 1018 div = (Math.ceil(div - epsilon)); 1019 break; 1020 case BigDecimal.ROUND_UNNECESSARY: 1021 if (div != Math.floor(div)) { 1022 throw new ArithmeticException("Rounding necessary"); 1023 } 1024 return number; 1025 default: 1026 1027 // Handle complex cases, where the choice depends on the closer value. 1028 1029 // We figure out the distances to the two possible values, ceiling and floor. 1030 // We then go for the diff that is smaller. Only if they are equal does the 1031 // mode matter. 1032 1033 double ceil = Math.ceil(div); 1034 double ceildiff = ceil - div; // (ceil * roundingInc) - number; 1035 double floor = Math.floor(div); 1036 double floordiff = div - floor; // number - (floor * roundingInc); 1037 1038 // Note that the diff values were those mapped back to the "normal" space by 1039 // using the roundingInc. I don't have access to the original author of the 1040 // code but suspect that that was to produce better result in edge cases 1041 // because of machine precision, rather than simply using the difference 1042 // between, say, ceil and div. However, it didn't work in all cases. Am 1043 // trying instead using an epsilon value. 1044 1045 switch (mode) { 1046 case BigDecimal.ROUND_HALF_EVEN: 1047 // We should be able to just return Math.rint(a), but this 1048 // doesn't work in some VMs. 1049 // if one is smaller than the other, take the corresponding side 1050 if (floordiff + epsilon < ceildiff) { 1051 div = floor; 1052 } else if (ceildiff + epsilon < floordiff) { 1053 div = ceil; 1054 } else { // they are equal, so we want to round to whichever is even 1055 double testFloor = floor / 2; 1056 div = (testFloor == Math.floor(testFloor)) ? floor : ceil; 1057 } 1058 break; 1059 case BigDecimal.ROUND_HALF_DOWN: 1060 div = ((floordiff <= ceildiff + epsilon) ? floor : ceil); 1061 break; 1062 case BigDecimal.ROUND_HALF_UP: 1063 div = ((ceildiff <= floordiff + epsilon) ? ceil : floor); 1064 break; 1065 default: 1066 throw new IllegalArgumentException("Invalid rounding mode: " + mode); 1067 } 1068 } 1069 number = roundingIncReciprocal == 0.0 ? div * roundingInc : div / roundingIncReciprocal; 1070 return number; 1071 } 1072 1073 private static double epsilon = 0.00000000001; 1074 1075 /** 1076 */ 1077 // [Spark/CDL] Delegate to format_long_StringBuffer_FieldPosition_boolean 1078 @Override 1079 public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) { 1080 return format(number, result, fieldPosition, false); 1081 } 1082 1083 private StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition, 1084 boolean parseAttr) { 1085 fieldPosition.setBeginIndex(0); 1086 fieldPosition.setEndIndex(0); 1087 1088 // If we are to do rounding, we need to move into the BigDecimal 1089 // domain in order to do divide/multiply correctly. 1090 if (actualRoundingIncrementICU != null) { 1091 return format(BigDecimal.valueOf(number), result, fieldPosition); 1092 } 1093 1094 boolean isNegative = (number < 0); 1095 if (isNegative) 1096 number = -number; 1097 1098 // In general, long values always represent real finite numbers, so we don't have 1099 // to check for +/- Infinity or NaN. However, there is one case we have to be 1100 // careful of: The multiplier can push a number near MIN_VALUE or MAX_VALUE 1101 // outside the legal range. We check for this before multiplying, and if it 1102 // happens we use BigInteger instead. 1103 if (multiplier != 1) { 1104 boolean tooBig = false; 1105 if (number < 0) { // This can only happen if number == Long.MIN_VALUE 1106 long cutoff = Long.MIN_VALUE / multiplier; 1107 tooBig = (number <= cutoff); // number == cutoff can only happen if multiplier == -1 1108 } else { 1109 long cutoff = Long.MAX_VALUE / multiplier; 1110 tooBig = (number > cutoff); 1111 } 1112 if (tooBig) { 1113 // [Spark/CDL] Use 1114 // format_BigInteger_StringBuffer_FieldPosition_boolean instead 1115 // parseAttr is used to judge whether to synthesize attributes. 1116 return format(BigInteger.valueOf(isNegative ? -number : number), result, 1117 fieldPosition, parseAttr); 1118 } 1119 } 1120 1121 number *= multiplier; 1122 synchronized (digitList) { 1123 digitList.set(number, precision(true)); 1124 // Issue 11808 1125 if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) { 1126 throw new ArithmeticException("Rounding necessary"); 1127 } 1128 return subformat(number, result, fieldPosition, isNegative, true, parseAttr); 1129 } 1130 } 1131 1132 /** 1133 * Formats a BigInteger number. 1134 */ 1135 @Override 1136 public StringBuffer format(BigInteger number, StringBuffer result, 1137 FieldPosition fieldPosition) { 1138 return format(number, result, fieldPosition, false); 1139 } 1140 1141 private StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition, 1142 boolean parseAttr) { 1143 // If we are to do rounding, we need to move into the BigDecimal 1144 // domain in order to do divide/multiply correctly. 1145 if (actualRoundingIncrementICU != null) { 1146 return format(new BigDecimal(number), result, fieldPosition); 1147 } 1148 1149 if (multiplier != 1) { 1150 number = number.multiply(BigInteger.valueOf(multiplier)); 1151 } 1152 1153 // At this point we are guaranteed a nonnegative finite 1154 // number. 1155 synchronized (digitList) { 1156 digitList.set(number, precision(true)); 1157 // For issue 11808. 1158 if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) { 1159 throw new ArithmeticException("Rounding necessary"); 1160 } 1161 return subformat(number.intValue(), result, fieldPosition, number.signum() < 0, true, 1162 parseAttr); 1163 } 1164 } 1165 1166 /** 1167 * Formats a BigDecimal number. 1168 */ 1169 @Override 1170 public StringBuffer format(java.math.BigDecimal number, StringBuffer result, 1171 FieldPosition fieldPosition) { 1172 return format(number, result, fieldPosition, false); 1173 } 1174 1175 private StringBuffer format(java.math.BigDecimal number, StringBuffer result, 1176 FieldPosition fieldPosition, 1177 boolean parseAttr) { 1178 if (multiplier != 1) { 1179 number = number.multiply(java.math.BigDecimal.valueOf(multiplier)); 1180 } 1181 1182 if (actualRoundingIncrement != null) { 1183 number = number.divide(actualRoundingIncrement, 0, roundingMode).multiply(actualRoundingIncrement); 1184 } 1185 1186 synchronized (digitList) { 1187 digitList.set(number, precision(false), !useExponentialNotation && 1188 !areSignificantDigitsUsed()); 1189 // For issue 11808. 1190 if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) { 1191 throw new ArithmeticException("Rounding necessary"); 1192 } 1193 return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0, 1194 false, parseAttr); 1195 } 1196 } 1197 1198 /** 1199 * Formats a BigDecimal number. 1200 */ 1201 @Override 1202 public StringBuffer format(BigDecimal number, StringBuffer result, 1203 FieldPosition fieldPosition) { 1204 // This method is just a copy of the corresponding java.math.BigDecimal method 1205 // for now. It isn't very efficient since it must create a conversion object to 1206 // do math on the rounding increment. In the future we may try to clean this up, 1207 // or even better, limit our support to just one flavor of BigDecimal. 1208 if (multiplier != 1) { 1209 number = number.multiply(BigDecimal.valueOf(multiplier), mathContext); 1210 } 1211 1212 if (actualRoundingIncrementICU != null) { 1213 number = number.divide(actualRoundingIncrementICU, 0, roundingMode) 1214 .multiply(actualRoundingIncrementICU, mathContext); 1215 } 1216 1217 synchronized (digitList) { 1218 digitList.set(number, precision(false), !useExponentialNotation && 1219 !areSignificantDigitsUsed()); 1220 // For issue 11808. 1221 if (digitList.wasRounded() && roundingMode == BigDecimal.ROUND_UNNECESSARY) { 1222 throw new ArithmeticException("Rounding necessary"); 1223 } 1224 return subformat(number.doubleValue(), result, fieldPosition, number.signum() < 0, 1225 false, false); 1226 } 1227 } 1228 1229 /** 1230 * Returns true if a grouping separator belongs at the given position, based on whether 1231 * grouping is in use and the values of the primary and secondary grouping interval. 1232 * 1233 * @param pos the number of integer digits to the right of the current position. Zero 1234 * indicates the position after the rightmost integer digit. 1235 * @return true if a grouping character belongs at the current position. 1236 */ 1237 private boolean isGroupingPosition(int pos) { 1238 boolean result = false; 1239 if (isGroupingUsed() && (pos > 0) && (groupingSize > 0)) { 1240 if ((groupingSize2 > 0) && (pos > groupingSize)) { 1241 result = ((pos - groupingSize) % groupingSize2) == 0; 1242 } else { 1243 result = pos % groupingSize == 0; 1244 } 1245 } 1246 return result; 1247 } 1248 1249 /** 1250 * Return the number of fraction digits to display, or the total 1251 * number of digits for significant digit formats and exponential 1252 * formats. 1253 */ 1254 private int precision(boolean isIntegral) { 1255 if (areSignificantDigitsUsed()) { 1256 return getMaximumSignificantDigits(); 1257 } else if (useExponentialNotation) { 1258 return getMinimumIntegerDigits() + getMaximumFractionDigits(); 1259 } else { 1260 return isIntegral ? 0 : getMaximumFractionDigits(); 1261 } 1262 } 1263 1264 private StringBuffer subformat(int number, StringBuffer result, FieldPosition fieldPosition, 1265 boolean isNegative, boolean isInteger, boolean parseAttr) { 1266 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 1267 // compute the plural category from the digitList plus other settings 1268 return subformat(currencyPluralInfo.select(getFixedDecimal(number)), 1269 result, fieldPosition, isNegative, 1270 isInteger, parseAttr); 1271 } else { 1272 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr); 1273 } 1274 } 1275 1276 /** 1277 * This is ugly, but don't see a better way to do it without major restructuring of the code. 1278 */ 1279 /*package*/ FixedDecimal getFixedDecimal(double number) { 1280 // get the visible fractions and the number of fraction digits. 1281 return getFixedDecimal(number, digitList); 1282 } 1283 1284 FixedDecimal getFixedDecimal(double number, DigitList dl) { 1285 int fractionalDigitsInDigitList = dl.count - dl.decimalAt; 1286 int v; 1287 long f; 1288 int maxFractionalDigits; 1289 int minFractionalDigits; 1290 if (useSignificantDigits) { 1291 maxFractionalDigits = maxSignificantDigits - dl.decimalAt; 1292 minFractionalDigits = minSignificantDigits - dl.decimalAt; 1293 if (minFractionalDigits < 0) { 1294 minFractionalDigits = 0; 1295 } 1296 if (maxFractionalDigits < 0) { 1297 maxFractionalDigits = 0; 1298 } 1299 } else { 1300 maxFractionalDigits = getMaximumFractionDigits(); 1301 minFractionalDigits = getMinimumFractionDigits(); 1302 } 1303 v = fractionalDigitsInDigitList; 1304 if (v < minFractionalDigits) { 1305 v = minFractionalDigits; 1306 } else if (v > maxFractionalDigits) { 1307 v = maxFractionalDigits; 1308 } 1309 f = 0; 1310 if (v > 0) { 1311 for (int i = Math.max(0, dl.decimalAt); i < dl.count; ++i) { 1312 f *= 10; 1313 f += (dl.digits[i] - '0'); 1314 } 1315 for (int i = v; i < fractionalDigitsInDigitList; ++i) { 1316 f *= 10; 1317 } 1318 } 1319 return new FixedDecimal(number, v, f); 1320 } 1321 1322 private StringBuffer subformat(double number, StringBuffer result, FieldPosition fieldPosition, 1323 boolean isNegative, 1324 boolean isInteger, boolean parseAttr) { 1325 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 1326 // compute the plural category from the digitList plus other settings 1327 return subformat(currencyPluralInfo.select(getFixedDecimal(number)), 1328 result, fieldPosition, isNegative, 1329 isInteger, parseAttr); 1330 } else { 1331 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr); 1332 } 1333 } 1334 1335 private StringBuffer subformat(String pluralCount, StringBuffer result, FieldPosition fieldPosition, 1336 boolean isNegative, boolean isInteger, boolean parseAttr) { 1337 // There are 2 ways to activate currency plural format: by applying a pattern with 1338 // 3 currency sign directly, or by instantiate a decimal formatter using 1339 // PLURALCURRENCYSTYLE. For both cases, the number of currency sign in the 1340 // pattern is 3. Even if the number of currency sign in the pattern is 3, it does 1341 // not mean we need to reset the pattern. For 1st case, we do not need to reset 1342 // pattern. For 2nd case, we might need to reset pattern, if the default pattern 1343 // (corresponding to plural count 'other') we use is different from the pattern 1344 // based on 'pluralCount'. 1345 // 1346 // style is only valid when decimal formatter is constructed through 1347 // DecimalFormat(pattern, symbol, style) 1348 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 1349 // May need to reset pattern if the style is PLURALCURRENCYSTYLE. 1350 String currencyPluralPattern = currencyPluralInfo.getCurrencyPluralPattern(pluralCount); 1351 if (formatPattern.equals(currencyPluralPattern) == false) { 1352 applyPatternWithoutExpandAffix(currencyPluralPattern, false); 1353 } 1354 } 1355 // Expand the affix to the right name according to the plural rule. This is only 1356 // used for currency plural formatting. Currency plural name is not a fixed 1357 // static one, it is a dynamic name based on the currency plural count. So, the 1358 // affixes need to be expanded here. For other cases, the affix is a static one 1359 // based on pattern alone, and it is already expanded during applying pattern, or 1360 // setDecimalFormatSymbols, or setCurrency. 1361 expandAffixAdjustWidth(pluralCount); 1362 return subformat(result, fieldPosition, isNegative, isInteger, parseAttr); 1363 } 1364 1365 /** 1366 * Complete the formatting of a finite number. On entry, the 1367 * digitList must be filled in with the correct digits. 1368 */ 1369 private StringBuffer subformat(StringBuffer result, FieldPosition fieldPosition, 1370 boolean isNegative, boolean isInteger, boolean parseAttr) { 1371 // NOTE: This isn't required anymore because DigitList takes care of this. 1372 // 1373 // // The negative of the exponent represents the number of leading // zeros 1374 // between the decimal and the first non-zero digit, for // a value < 0.1 (e.g., 1375 // for 0.00123, -fExponent == 2). If this // is more than the maximum fraction 1376 // digits, then we have an underflow // for the printed representation. We 1377 // recognize this here and set // the DigitList representation to zero in this 1378 // situation. 1379 // 1380 // if (-digitList.decimalAt >= getMaximumFractionDigits()) 1381 // { 1382 // digitList.count = 0; 1383 // } 1384 1385 1386 1387 // Per bug 4147706, DecimalFormat must respect the sign of numbers which format as 1388 // zero. This allows sensible computations and preserves relations such as 1389 // signum(1/x) = signum(x), where x is +Infinity or -Infinity. Prior to this fix, 1390 // we always formatted zero values as if they were positive. Liu 7/6/98. 1391 if (digitList.isZero()) { 1392 digitList.decimalAt = 0; // Normalize 1393 } 1394 1395 int prefixLen = appendAffix(result, isNegative, true, fieldPosition, parseAttr); 1396 1397 if (useExponentialNotation) { 1398 subformatExponential(result, fieldPosition, parseAttr); 1399 } else { 1400 subformatFixed(result, fieldPosition, isInteger, parseAttr); 1401 } 1402 1403 int suffixLen = appendAffix(result, isNegative, false, fieldPosition, parseAttr); 1404 addPadding(result, fieldPosition, prefixLen, suffixLen); 1405 return result; 1406 } 1407 1408 private void subformatFixed(StringBuffer result, 1409 FieldPosition fieldPosition, 1410 boolean isInteger, 1411 boolean parseAttr) { 1412 String[] digits = symbols.getDigitStrings(); 1413 1414 String grouping = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ? 1415 symbols.getGroupingSeparatorString(): symbols.getMonetaryGroupingSeparatorString(); 1416 String decimal = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ? 1417 symbols.getDecimalSeparatorString() : symbols.getMonetaryDecimalSeparatorString(); 1418 boolean useSigDig = areSignificantDigitsUsed(); 1419 int maxIntDig = getMaximumIntegerDigits(); 1420 int minIntDig = getMinimumIntegerDigits(); 1421 int i; 1422 // [Spark/CDL] Record the integer start index. 1423 int intBegin = result.length(); 1424 // Record field information for caller. 1425 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD || 1426 fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 1427 fieldPosition.setBeginIndex(intBegin); 1428 } 1429 long fractionalDigits = 0; 1430 int fractionalDigitsCount = 0; 1431 boolean recordFractionDigits = false; 1432 1433 int sigCount = 0; 1434 int minSigDig = getMinimumSignificantDigits(); 1435 int maxSigDig = getMaximumSignificantDigits(); 1436 if (!useSigDig) { 1437 minSigDig = 0; 1438 maxSigDig = Integer.MAX_VALUE; 1439 } 1440 1441 // Output the integer portion. Here 'count' is the total number of integer 1442 // digits we will display, including both leading zeros required to satisfy 1443 // getMinimumIntegerDigits, and actual digits present in the number. 1444 int count = useSigDig ? Math.max(1, digitList.decimalAt) : minIntDig; 1445 if (digitList.decimalAt > 0 && count < digitList.decimalAt) { 1446 count = digitList.decimalAt; 1447 } 1448 1449 // Handle the case where getMaximumIntegerDigits() is smaller than the real 1450 // number of integer digits. If this is so, we output the least significant 1451 // max integer digits. For example, the value 1997 printed with 2 max integer 1452 // digits is just "97". 1453 1454 int digitIndex = 0; // Index into digitList.fDigits[] 1455 if (count > maxIntDig && maxIntDig >= 0) { 1456 count = maxIntDig; 1457 digitIndex = digitList.decimalAt - count; 1458 } 1459 1460 int sizeBeforeIntegerPart = result.length(); 1461 for (i = count - 1; i >= 0; --i) { 1462 if (i < digitList.decimalAt && digitIndex < digitList.count 1463 && sigCount < maxSigDig) { 1464 // Output a real digit 1465 result.append(digits[digitList.getDigitValue(digitIndex++)]); 1466 ++sigCount; 1467 } else { 1468 // Output a zero (leading or trailing) 1469 result.append(digits[0]); 1470 if (sigCount > 0) { 1471 ++sigCount; 1472 } 1473 } 1474 1475 // Output grouping separator if necessary. 1476 if (isGroupingPosition(i)) { 1477 result.append(grouping); 1478 // [Spark/CDL] Add grouping separator attribute here. 1479 // Set only for the first instance. 1480 // Length of grouping separator is 1. 1481 if (fieldPosition.getFieldAttribute() == Field.GROUPING_SEPARATOR && 1482 fieldPosition.getBeginIndex() == 0 && fieldPosition.getEndIndex() == 0) { 1483 fieldPosition.setBeginIndex(result.length()-1); 1484 fieldPosition.setEndIndex(result.length()); 1485 } 1486 if (parseAttr) { 1487 addAttribute(Field.GROUPING_SEPARATOR, result.length() - 1, result.length()); 1488 } 1489 } 1490 } 1491 1492 // Record field information for caller. 1493 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD || 1494 fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 1495 fieldPosition.setEndIndex(result.length()); 1496 } 1497 1498 // This handles the special case of formatting 0. For zero only, we count the 1499 // zero to the left of the decimal point as one signficant digit. Ordinarily we 1500 // do not count any leading 0's as significant. If the number we are formatting 1501 // is not zero, then either sigCount or digits.getCount() will be non-zero. 1502 if (sigCount == 0 && digitList.count == 0) { 1503 sigCount = 1; 1504 } 1505 1506 // Determine whether or not there are any printable fractional digits. If 1507 // we've used up the digits we know there aren't. 1508 boolean fractionPresent = (!isInteger && digitIndex < digitList.count) 1509 || (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0)); 1510 1511 // If there is no fraction present, and we haven't printed any integer digits, 1512 // then print a zero. Otherwise we won't print _any_ digits, and we won't be 1513 // able to parse this string. 1514 if (!fractionPresent && result.length() == sizeBeforeIntegerPart) 1515 result.append(digits[0]); 1516 // [Spark/CDL] Add attribute for integer part. 1517 if (parseAttr) { 1518 addAttribute(Field.INTEGER, intBegin, result.length()); 1519 } 1520 // Output the decimal separator if we always do so. 1521 if (decimalSeparatorAlwaysShown || fractionPresent) { 1522 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1523 fieldPosition.setBeginIndex(result.length()); 1524 } 1525 result.append(decimal); 1526 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1527 fieldPosition.setEndIndex(result.length()); 1528 } 1529 // [Spark/CDL] Add attribute for decimal separator 1530 if (parseAttr) { 1531 addAttribute(Field.DECIMAL_SEPARATOR, result.length() - 1, result.length()); 1532 } 1533 } 1534 1535 // Record field information for caller. 1536 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) { 1537 fieldPosition.setBeginIndex(result.length()); 1538 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) { 1539 fieldPosition.setBeginIndex(result.length()); 1540 } 1541 1542 // [Spark/CDL] Record the begin index of fraction part. 1543 int fracBegin = result.length(); 1544 recordFractionDigits = fieldPosition instanceof UFieldPosition; 1545 1546 count = useSigDig ? Integer.MAX_VALUE : getMaximumFractionDigits(); 1547 if (useSigDig && (sigCount == maxSigDig || 1548 (sigCount >= minSigDig && digitIndex == digitList.count))) { 1549 count = 0; 1550 } 1551 for (i = 0; i < count; ++i) { 1552 // Here is where we escape from the loop. We escape if we've output the 1553 // maximum fraction digits (specified in the for expression above). We 1554 // also stop when we've output the minimum digits and either: we have an 1555 // integer, so there is no fractional stuff to display, or we're out of 1556 // significant digits. 1557 if (!useSigDig && i >= getMinimumFractionDigits() && 1558 (isInteger || digitIndex >= digitList.count)) { 1559 break; 1560 } 1561 1562 // Output leading fractional zeros. These are zeros that come after the 1563 // decimal but before any significant digits. These are only output if 1564 // abs(number being formatted) < 1.0. 1565 if (-1 - i > (digitList.decimalAt - 1)) { 1566 result.append(digits[0]); 1567 if (recordFractionDigits) { 1568 ++fractionalDigitsCount; 1569 fractionalDigits *= 10; 1570 } 1571 continue; 1572 } 1573 1574 // Output a digit, if we have any precision left, or a zero if we 1575 // don't. We don't want to output noise digits. 1576 if (!isInteger && digitIndex < digitList.count) { 1577 byte digit = digitList.getDigitValue(digitIndex++); 1578 result.append(digits[digit]); 1579 if (recordFractionDigits) { 1580 ++fractionalDigitsCount; 1581 fractionalDigits *= 10; 1582 fractionalDigits += digit; 1583 } 1584 } else { 1585 result.append(digits[0]); 1586 if (recordFractionDigits) { 1587 ++fractionalDigitsCount; 1588 fractionalDigits *= 10; 1589 } 1590 } 1591 1592 // If we reach the maximum number of significant digits, or if we output 1593 // all the real digits and reach the minimum, then we are done. 1594 ++sigCount; 1595 if (useSigDig && (sigCount == maxSigDig || 1596 (digitIndex == digitList.count && sigCount >= minSigDig))) { 1597 break; 1598 } 1599 } 1600 1601 // Record field information for caller. 1602 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) { 1603 fieldPosition.setEndIndex(result.length()); 1604 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) { 1605 fieldPosition.setEndIndex(result.length()); 1606 } 1607 if (recordFractionDigits) { 1608 ((UFieldPosition) fieldPosition).setFractionDigits(fractionalDigitsCount, fractionalDigits); 1609 } 1610 1611 // [Spark/CDL] Add attribute information if necessary. 1612 if (parseAttr && (decimalSeparatorAlwaysShown || fractionPresent)) { 1613 addAttribute(Field.FRACTION, fracBegin, result.length()); 1614 } 1615 } 1616 1617 private void subformatExponential(StringBuffer result, 1618 FieldPosition fieldPosition, 1619 boolean parseAttr) { 1620 String[] digits = symbols.getDigitStringsLocal(); 1621 String decimal = currencySignCount == CURRENCY_SIGN_COUNT_ZERO ? 1622 symbols.getDecimalSeparatorString() : symbols.getMonetaryDecimalSeparatorString(); 1623 boolean useSigDig = areSignificantDigitsUsed(); 1624 int maxIntDig = getMaximumIntegerDigits(); 1625 int minIntDig = getMinimumIntegerDigits(); 1626 int i; 1627 // Record field information for caller. 1628 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 1629 fieldPosition.setBeginIndex(result.length()); 1630 fieldPosition.setEndIndex(-1); 1631 } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) { 1632 fieldPosition.setBeginIndex(-1); 1633 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 1634 fieldPosition.setBeginIndex(result.length()); 1635 fieldPosition.setEndIndex(-1); 1636 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) { 1637 fieldPosition.setBeginIndex(-1); 1638 } 1639 1640 // [Spark/CDL] 1641 // the begin index of integer part 1642 // the end index of integer part 1643 // the begin index of fractional part 1644 int intBegin = result.length(); 1645 int intEnd = -1; 1646 int fracBegin = -1; 1647 int minFracDig = 0; 1648 if (useSigDig) { 1649 maxIntDig = minIntDig = 1; 1650 minFracDig = getMinimumSignificantDigits() - 1; 1651 } else { 1652 minFracDig = getMinimumFractionDigits(); 1653 if (maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) { 1654 maxIntDig = 1; 1655 if (maxIntDig < minIntDig) { 1656 maxIntDig = minIntDig; 1657 } 1658 } 1659 if (maxIntDig > minIntDig) { 1660 minIntDig = 1; 1661 } 1662 } 1663 long fractionalDigits = 0; 1664 int fractionalDigitsCount = 0; 1665 boolean recordFractionDigits = false; 1666 1667 // Minimum integer digits are handled in exponential format by adjusting the 1668 // exponent. For example, 0.01234 with 3 minimum integer digits is "123.4E-4". 1669 1670 // Maximum integer digits are interpreted as indicating the repeating 1671 // range. This is useful for engineering notation, in which the exponent is 1672 // restricted to a multiple of 3. For example, 0.01234 with 3 maximum integer 1673 // digits is "12.34e-3". If maximum integer digits are defined and are larger 1674 // than minimum integer digits, then minimum integer digits are ignored. 1675 1676 int exponent = digitList.decimalAt; 1677 if (maxIntDig > 1 && maxIntDig != minIntDig) { 1678 // A exponent increment is defined; adjust to it. 1679 exponent = (exponent > 0) ? (exponent - 1) / maxIntDig : (exponent / maxIntDig) - 1; 1680 exponent *= maxIntDig; 1681 } else { 1682 // No exponent increment is defined; use minimum integer digits. 1683 // If none is specified, as in "#E0", generate 1 integer digit. 1684 exponent -= (minIntDig > 0 || minFracDig > 0) ? minIntDig : 1; 1685 } 1686 1687 // We now output a minimum number of digits, and more if there are more 1688 // digits, up to the maximum number of digits. We place the decimal point 1689 // after the "integer" digits, which are the first (decimalAt - exponent) 1690 // digits. 1691 int minimumDigits = minIntDig + minFracDig; 1692 // The number of integer digits is handled specially if the number 1693 // is zero, since then there may be no digits. 1694 int integerDigits = digitList.isZero() ? minIntDig : digitList.decimalAt - exponent; 1695 int totalDigits = digitList.count; 1696 if (minimumDigits > totalDigits) 1697 totalDigits = minimumDigits; 1698 if (integerDigits > totalDigits) 1699 totalDigits = integerDigits; 1700 1701 for (i = 0; i < totalDigits; ++i) { 1702 if (i == integerDigits) { 1703 // Record field information for caller. 1704 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 1705 fieldPosition.setEndIndex(result.length()); 1706 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 1707 fieldPosition.setEndIndex(result.length()); 1708 } 1709 1710 // [Spark/CDL] Add attribute for integer part 1711 if (parseAttr) { 1712 intEnd = result.length(); 1713 addAttribute(Field.INTEGER, intBegin, result.length()); 1714 } 1715 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1716 fieldPosition.setBeginIndex(result.length()); 1717 } 1718 result.append(decimal); 1719 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1720 fieldPosition.setEndIndex(result.length()); 1721 } 1722 // [Spark/CDL] Add attribute for decimal separator 1723 fracBegin = result.length(); 1724 if (parseAttr) { 1725 // Length of decimal separator is 1. 1726 int decimalSeparatorBegin = result.length() - 1; 1727 addAttribute(Field.DECIMAL_SEPARATOR, decimalSeparatorBegin, 1728 result.length()); 1729 } 1730 // Record field information for caller. 1731 if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) { 1732 fieldPosition.setBeginIndex(result.length()); 1733 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) { 1734 fieldPosition.setBeginIndex(result.length()); 1735 } 1736 recordFractionDigits = fieldPosition instanceof UFieldPosition; 1737 1738 } 1739 byte digit = (i < digitList.count) ? digitList.getDigitValue(i) : (byte)0; 1740 result.append(digits[digit]); 1741 if (recordFractionDigits) { 1742 ++fractionalDigitsCount; 1743 fractionalDigits *= 10; 1744 fractionalDigits += digit; 1745 } 1746 } 1747 1748 // For ICU compatibility and format 0 to 0E0 with pattern "#E0" [Richard/GCL] 1749 if (digitList.isZero() && (totalDigits == 0)) { 1750 result.append(digits[0]); 1751 } 1752 1753 // add the decimal separator if it is to be always shown AND there are no decimal digits 1754 if ((fracBegin == -1) && this.decimalSeparatorAlwaysShown) { 1755 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1756 fieldPosition.setBeginIndex(result.length()); 1757 } 1758 result.append(decimal); 1759 if (fieldPosition.getFieldAttribute() == Field.DECIMAL_SEPARATOR) { 1760 fieldPosition.setEndIndex(result.length()); 1761 } 1762 if (parseAttr) { 1763 // Length of decimal separator is 1. 1764 int decimalSeparatorBegin = result.length() - 1; 1765 addAttribute(Field.DECIMAL_SEPARATOR, decimalSeparatorBegin, result.length()); 1766 } 1767 } 1768 1769 // Record field information 1770 if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD) { 1771 if (fieldPosition.getEndIndex() < 0) { 1772 fieldPosition.setEndIndex(result.length()); 1773 } 1774 } else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD) { 1775 if (fieldPosition.getBeginIndex() < 0) { 1776 fieldPosition.setBeginIndex(result.length()); 1777 } 1778 fieldPosition.setEndIndex(result.length()); 1779 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.INTEGER) { 1780 if (fieldPosition.getEndIndex() < 0) { 1781 fieldPosition.setEndIndex(result.length()); 1782 } 1783 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.FRACTION) { 1784 if (fieldPosition.getBeginIndex() < 0) { 1785 fieldPosition.setBeginIndex(result.length()); 1786 } 1787 fieldPosition.setEndIndex(result.length()); 1788 } 1789 if (recordFractionDigits) { 1790 ((UFieldPosition) fieldPosition).setFractionDigits(fractionalDigitsCount, fractionalDigits); 1791 } 1792 1793 // [Spark/CDL] Calculate the end index of integer part and fractional 1794 // part if they are not properly processed yet. 1795 if (parseAttr) { 1796 if (intEnd < 0) { 1797 addAttribute(Field.INTEGER, intBegin, result.length()); 1798 } 1799 if (fracBegin > 0) { 1800 addAttribute(Field.FRACTION, fracBegin, result.length()); 1801 } 1802 } 1803 1804 // The exponent is output using the pattern-specified minimum exponent 1805 // digits. There is no maximum limit to the exponent digits, since truncating 1806 // the exponent would result in an unacceptable inaccuracy. 1807 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SYMBOL) { 1808 fieldPosition.setBeginIndex(result.length()); 1809 } 1810 1811 result.append(symbols.getExponentSeparator()); 1812 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SYMBOL) { 1813 fieldPosition.setEndIndex(result.length()); 1814 } 1815 // [Spark/CDL] For exponent symbol, add an attribute. 1816 if (parseAttr) { 1817 addAttribute(Field.EXPONENT_SYMBOL, result.length() - 1818 symbols.getExponentSeparator().length(), result.length()); 1819 } 1820 // For zero values, we force the exponent to zero. We must do this here, and 1821 // not earlier, because the value is used to determine integer digit count 1822 // above. 1823 if (digitList.isZero()) 1824 exponent = 0; 1825 1826 boolean negativeExponent = exponent < 0; 1827 if (negativeExponent) { 1828 exponent = -exponent; 1829 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SIGN) { 1830 fieldPosition.setBeginIndex(result.length()); 1831 } 1832 result.append(symbols.getMinusSignString()); 1833 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SIGN) { 1834 fieldPosition.setEndIndex(result.length()); 1835 } 1836 // [Spark/CDL] If exponent has sign, then add an exponent sign 1837 // attribute. 1838 if (parseAttr) { 1839 // Length of exponent sign is 1. 1840 addAttribute(Field.EXPONENT_SIGN, result.length() - 1, result.length()); 1841 } 1842 } else if (exponentSignAlwaysShown) { 1843 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SIGN) { 1844 fieldPosition.setBeginIndex(result.length()); 1845 } 1846 result.append(symbols.getPlusSignString()); 1847 if (fieldPosition.getFieldAttribute() == Field.EXPONENT_SIGN) { 1848 fieldPosition.setEndIndex(result.length()); 1849 } 1850 // [Spark/CDL] Add an plus sign attribute. 1851 if (parseAttr) { 1852 // Length of exponent sign is 1. 1853 int expSignBegin = result.length() - 1; 1854 addAttribute(Field.EXPONENT_SIGN, expSignBegin, result.length()); 1855 } 1856 } 1857 int expBegin = result.length(); 1858 digitList.set(exponent); 1859 { 1860 int expDig = minExponentDigits; 1861 if (useExponentialNotation && expDig < 1) { 1862 expDig = 1; 1863 } 1864 for (i = digitList.decimalAt; i < expDig; ++i) 1865 result.append(digits[0]); 1866 } 1867 for (i = 0; i < digitList.decimalAt; ++i) { 1868 result.append((i < digitList.count) ? digits[digitList.getDigitValue(i)] 1869 : digits[0]); 1870 } 1871 // [Spark/CDL] Add attribute for exponent part. 1872 if (fieldPosition.getFieldAttribute() == Field.EXPONENT) { 1873 fieldPosition.setBeginIndex(expBegin); 1874 fieldPosition.setEndIndex(result.length()); 1875 } 1876 if (parseAttr) { 1877 addAttribute(Field.EXPONENT, expBegin, result.length()); 1878 } 1879 } 1880 1881 private final void addPadding(StringBuffer result, FieldPosition fieldPosition, int prefixLen, 1882 int suffixLen) { 1883 if (formatWidth > 0) { 1884 int len = formatWidth - result.length(); 1885 if (len > 0) { 1886 char[] padding = new char[len]; 1887 for (int i = 0; i < len; ++i) { 1888 padding[i] = pad; 1889 } 1890 switch (padPosition) { 1891 case PAD_AFTER_PREFIX: 1892 result.insert(prefixLen, padding); 1893 break; 1894 case PAD_BEFORE_PREFIX: 1895 result.insert(0, padding); 1896 break; 1897 case PAD_BEFORE_SUFFIX: 1898 result.insert(result.length() - suffixLen, padding); 1899 break; 1900 case PAD_AFTER_SUFFIX: 1901 result.append(padding); 1902 break; 1903 } 1904 if (padPosition == PAD_BEFORE_PREFIX || padPosition == PAD_AFTER_PREFIX) { 1905 fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + len); 1906 fieldPosition.setEndIndex(fieldPosition.getEndIndex() + len); 1907 } 1908 } 1909 } 1910 } 1911 1912 /** 1913 * Parses the given string, returning a <code>Number</code> object to represent the 1914 * parsed value. <code>Double</code> objects are returned to represent non-integral 1915 * values which cannot be stored in a <code>BigDecimal</code>. These are 1916 * <code>NaN</code>, infinity, -infinity, and -0.0. If {@link #isParseBigDecimal()} is 1917 * false (the default), all other values are returned as <code>Long</code>, 1918 * <code>BigInteger</code>, or <code>BigDecimal</code> values, in that order of 1919 * preference. If {@link #isParseBigDecimal()} is true, all other values are returned 1920 * as <code>BigDecimal</code> valuse. If the parse fails, null is returned. 1921 * 1922 * @param text the string to be parsed 1923 * @param parsePosition defines the position where parsing is to begin, and upon 1924 * return, the position where parsing left off. If the position has not changed upon 1925 * return, then parsing failed. 1926 * @return a <code>Number</code> object with the parsed value or 1927 * <code>null</code> if the parse failed 1928 */ 1929 @Override 1930 public Number parse(String text, ParsePosition parsePosition) { 1931 return (Number) parse(text, parsePosition, null); 1932 } 1933 1934 /** 1935 * Parses text from the given string as a CurrencyAmount. Unlike the parse() method, 1936 * this method will attempt to parse a generic currency name, searching for a match of 1937 * this object's locale's currency display names, or for a 3-letter ISO currency 1938 * code. This method will fail if this format is not a currency format, that is, if it 1939 * does not contain the currency pattern symbol (U+00A4) in its prefix or suffix. 1940 * 1941 * @param text the text to parse 1942 * @param pos input-output position; on input, the position within text to match; must 1943 * have 0 <= pos.getIndex() < text.length(); on output, the position after the last 1944 * matched character. If the parse fails, the position in unchanged upon output. 1945 * @return a CurrencyAmount, or null upon failure 1946 */ 1947 @Override 1948 public CurrencyAmount parseCurrency(CharSequence text, ParsePosition pos) { 1949 Currency[] currency = new Currency[1]; 1950 return (CurrencyAmount) parse(text.toString(), pos, currency); 1951 } 1952 1953 /** 1954 * Parses the given text as either a Number or a CurrencyAmount. 1955 * 1956 * @param text the string to parse 1957 * @param parsePosition input-output position; on input, the position within text to 1958 * match; must have 0 <= pos.getIndex() < text.length(); on output, the position after 1959 * the last matched character. If the parse fails, the position in unchanged upon 1960 * output. 1961 * @param currency if non-null, a CurrencyAmount is parsed and returned; otherwise a 1962 * Number is parsed and returned 1963 * @return a Number or CurrencyAmount or null 1964 */ 1965 private Object parse(String text, ParsePosition parsePosition, Currency[] currency) { 1966 int backup; 1967 int i = backup = parsePosition.getIndex(); 1968 1969 // Handle NaN as a special case: 1970 1971 // Skip padding characters, if around prefix 1972 if (formatWidth > 0 && 1973 (padPosition == PAD_BEFORE_PREFIX || padPosition == PAD_AFTER_PREFIX)) { 1974 i = skipPadding(text, i); 1975 } 1976 if (text.regionMatches(i, symbols.getNaN(), 0, symbols.getNaN().length())) { 1977 i += symbols.getNaN().length(); 1978 // Skip padding characters, if around suffix 1979 if (formatWidth > 0 && (padPosition == PAD_BEFORE_SUFFIX || 1980 padPosition == PAD_AFTER_SUFFIX)) { 1981 i = skipPadding(text, i); 1982 } 1983 parsePosition.setIndex(i); 1984 return new Double(Double.NaN); 1985 } 1986 1987 // NaN parse failed; start over 1988 i = backup; 1989 1990 boolean[] status = new boolean[STATUS_LENGTH]; 1991 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) { 1992 if (!parseForCurrency(text, parsePosition, currency, status)) { 1993 return null; 1994 } 1995 } else if (currency != null) { 1996 return null; 1997 } else { 1998 if (!subparse(text, parsePosition, digitList, status, currency, negPrefixPattern, 1999 negSuffixPattern, posPrefixPattern, posSuffixPattern, 2000 false, Currency.SYMBOL_NAME)) { 2001 parsePosition.setIndex(backup); 2002 return null; 2003 } 2004 } 2005 2006 Number n = null; 2007 2008 // Handle infinity 2009 if (status[STATUS_INFINITE]) { 2010 n = new Double(status[STATUS_POSITIVE] ? Double.POSITIVE_INFINITY : 2011 Double.NEGATIVE_INFINITY); 2012 } 2013 2014 // Handle underflow 2015 else if (status[STATUS_UNDERFLOW]) { 2016 n = status[STATUS_POSITIVE] ? new Double("0.0") : new Double("-0.0"); 2017 } 2018 2019 // Handle -0.0 2020 else if (!status[STATUS_POSITIVE] && digitList.isZero()) { 2021 n = new Double("-0.0"); 2022 } 2023 2024 else { 2025 // Do as much of the multiplier conversion as possible without 2026 // losing accuracy. 2027 int mult = multiplier; // Don't modify this.multiplier 2028 while (mult % 10 == 0) { 2029 --digitList.decimalAt; 2030 mult /= 10; 2031 } 2032 2033 // Handle integral values 2034 if (!parseBigDecimal && mult == 1 && digitList.isIntegral()) { 2035 // hack quick long 2036 if (digitList.decimalAt < 12) { // quick check for long 2037 long l = 0; 2038 if (digitList.count > 0) { 2039 int nx = 0; 2040 while (nx < digitList.count) { 2041 l = l * 10 + (char) digitList.digits[nx++] - '0'; 2042 } 2043 while (nx++ < digitList.decimalAt) { 2044 l *= 10; 2045 } 2046 if (!status[STATUS_POSITIVE]) { 2047 l = -l; 2048 } 2049 } 2050 n = Long.valueOf(l); 2051 } else { 2052 BigInteger big = digitList.getBigInteger(status[STATUS_POSITIVE]); 2053 n = (big.bitLength() < 64) ? (Number) Long.valueOf(big.longValue()) : (Number) big; 2054 } 2055 } 2056 // Handle non-integral values or the case where parseBigDecimal is set 2057 else { 2058 BigDecimal big = digitList.getBigDecimalICU(status[STATUS_POSITIVE]); 2059 n = big; 2060 if (mult != 1) { 2061 n = big.divide(BigDecimal.valueOf(mult), mathContext); 2062 } 2063 } 2064 } 2065 2066 // Assemble into CurrencyAmount if necessary 2067 return (currency != null) ? (Object) new CurrencyAmount(n, currency[0]) : (Object) n; 2068 } 2069 2070 private boolean parseForCurrency(String text, ParsePosition parsePosition, 2071 Currency[] currency, boolean[] status) { 2072 int origPos = parsePosition.getIndex(); 2073 if (!isReadyForParsing) { 2074 int savedCurrencySignCount = currencySignCount; 2075 setupCurrencyAffixForAllPatterns(); 2076 // reset pattern back 2077 if (savedCurrencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 2078 applyPatternWithoutExpandAffix(formatPattern, false); 2079 } else { 2080 applyPattern(formatPattern, false); 2081 } 2082 isReadyForParsing = true; 2083 } 2084 int maxPosIndex = origPos; 2085 int maxErrorPos = -1; 2086 boolean[] savedStatus = null; 2087 // First, parse against current pattern. 2088 // Since current pattern could be set by applyPattern(), 2089 // it could be an arbitrary pattern, and it may not be the one 2090 // defined in current locale. 2091 boolean[] tmpStatus = new boolean[STATUS_LENGTH]; 2092 ParsePosition tmpPos = new ParsePosition(origPos); 2093 DigitList tmpDigitList = new DigitList(); 2094 boolean found; 2095 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 2096 found = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency, 2097 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern, 2098 true, Currency.LONG_NAME); 2099 } else { 2100 found = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency, 2101 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern, 2102 true, Currency.SYMBOL_NAME); 2103 } 2104 if (found) { 2105 if (tmpPos.getIndex() > maxPosIndex) { 2106 maxPosIndex = tmpPos.getIndex(); 2107 savedStatus = tmpStatus; 2108 digitList = tmpDigitList; 2109 } 2110 } else { 2111 maxErrorPos = tmpPos.getErrorIndex(); 2112 } 2113 // Then, parse against affix patterns. Those are currency patterns and currency 2114 // plural patterns defined in the locale. 2115 for (AffixForCurrency affix : affixPatternsForCurrency) { 2116 tmpStatus = new boolean[STATUS_LENGTH]; 2117 tmpPos = new ParsePosition(origPos); 2118 tmpDigitList = new DigitList(); 2119 boolean result = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency, 2120 affix.getNegPrefix(), affix.getNegSuffix(), 2121 affix.getPosPrefix(), affix.getPosSuffix(), 2122 true, affix.getPatternType()); 2123 if (result) { 2124 found = true; 2125 if (tmpPos.getIndex() > maxPosIndex) { 2126 maxPosIndex = tmpPos.getIndex(); 2127 savedStatus = tmpStatus; 2128 digitList = tmpDigitList; 2129 } 2130 } else { 2131 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? tmpPos.getErrorIndex() 2132 : maxErrorPos; 2133 } 2134 } 2135 // Finally, parse against simple affix to find the match. For example, in 2136 // TestMonster suite, if the to-be-parsed text is "-\u00A40,00". 2137 // complexAffixCompare will not find match, since there is no ISO code matches 2138 // "\u00A4", and the parse stops at "\u00A4". We will just use simple affix 2139 // comparison (look for exact match) to pass it. 2140 // 2141 // TODO: We should parse against simple affix first when 2142 // output currency is not requested. After the complex currency 2143 // parsing implementation was introduced, the default currency 2144 // instance parsing slowed down because of the new code flow. 2145 // I filed #10312 - Yoshito 2146 tmpStatus = new boolean[STATUS_LENGTH]; 2147 tmpPos = new ParsePosition(origPos); 2148 tmpDigitList = new DigitList(); 2149 2150 // Disable complex currency parsing and try it again. 2151 boolean result = subparse(text, tmpPos, tmpDigitList, tmpStatus, currency, 2152 negativePrefix, negativeSuffix, positivePrefix, positiveSuffix, 2153 false /* disable complex currency parsing */, Currency.SYMBOL_NAME); 2154 if (result) { 2155 if (tmpPos.getIndex() > maxPosIndex) { 2156 maxPosIndex = tmpPos.getIndex(); 2157 savedStatus = tmpStatus; 2158 digitList = tmpDigitList; 2159 } 2160 found = true; 2161 } else { 2162 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? tmpPos.getErrorIndex() : 2163 maxErrorPos; 2164 } 2165 2166 if (!found) { 2167 // parsePosition.setIndex(origPos); 2168 parsePosition.setErrorIndex(maxErrorPos); 2169 } else { 2170 parsePosition.setIndex(maxPosIndex); 2171 parsePosition.setErrorIndex(-1); 2172 for (int index = 0; index < STATUS_LENGTH; ++index) { 2173 status[index] = savedStatus[index]; 2174 } 2175 } 2176 return found; 2177 } 2178 2179 // Get affix patterns used in locale's currency pattern (NumberPatterns[1]) and 2180 // currency plural pattern (CurrencyUnitPatterns). 2181 private void setupCurrencyAffixForAllPatterns() { 2182 if (currencyPluralInfo == null) { 2183 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale()); 2184 } 2185 affixPatternsForCurrency = new HashSet<AffixForCurrency>(); 2186 2187 // save the current pattern, since it will be changed by 2188 // applyPatternWithoutExpandAffix 2189 String savedFormatPattern = formatPattern; 2190 2191 // CURRENCYSTYLE and ISOCURRENCYSTYLE should have the same prefix and suffix, so, 2192 // only need to save one of them. Here, chose onlyApplyPatternWithoutExpandAffix 2193 // without saving the actualy pattern in 'pattern' data member. TODO: is it uloc? 2194 applyPatternWithoutExpandAffix(getPattern(symbols.getULocale(), NumberFormat.CURRENCYSTYLE), 2195 false); 2196 AffixForCurrency affixes = new AffixForCurrency( 2197 negPrefixPattern, negSuffixPattern, posPrefixPattern, posSuffixPattern, 2198 Currency.SYMBOL_NAME); 2199 affixPatternsForCurrency.add(affixes); 2200 2201 // add plural pattern 2202 Iterator<String> iter = currencyPluralInfo.pluralPatternIterator(); 2203 Set<String> currencyUnitPatternSet = new HashSet<String>(); 2204 while (iter.hasNext()) { 2205 String pluralCount = iter.next(); 2206 String currencyPattern = currencyPluralInfo.getCurrencyPluralPattern(pluralCount); 2207 if (currencyPattern != null && 2208 currencyUnitPatternSet.contains(currencyPattern) == false) { 2209 currencyUnitPatternSet.add(currencyPattern); 2210 applyPatternWithoutExpandAffix(currencyPattern, false); 2211 affixes = new AffixForCurrency(negPrefixPattern, negSuffixPattern, posPrefixPattern, 2212 posSuffixPattern, Currency.LONG_NAME); 2213 affixPatternsForCurrency.add(affixes); 2214 } 2215 } 2216 // reset pattern back 2217 formatPattern = savedFormatPattern; 2218 } 2219 2220 // currency formatting style options 2221 private static final int CURRENCY_SIGN_COUNT_ZERO = 0; 2222 private static final int CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT = 1; 2223 private static final int CURRENCY_SIGN_COUNT_IN_ISO_FORMAT = 2; 2224 private static final int CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT = 3; 2225 2226 private static final int STATUS_INFINITE = 0; 2227 private static final int STATUS_POSITIVE = 1; 2228 private static final int STATUS_UNDERFLOW = 2; 2229 private static final int STATUS_LENGTH = 3; 2230 2231 private static final UnicodeSet dotEquivalents = new UnicodeSet( 2232 //"[.\u2024\u3002\uFE12\uFE52\uFF0E\uFF61]" 2233 0x002E, 0x002E, 2234 0x2024, 0x2024, 2235 0x3002, 0x3002, 2236 0xFE12, 0xFE12, 2237 0xFE52, 0xFE52, 2238 0xFF0E, 0xFF0E, 2239 0xFF61, 0xFF61).freeze(); 2240 2241 private static final UnicodeSet commaEquivalents = new UnicodeSet( 2242 //"[,\u060C\u066B\u3001\uFE10\uFE11\uFE50\uFE51\uFF0C\uFF64]" 2243 0x002C, 0x002C, 2244 0x060C, 0x060C, 2245 0x066B, 0x066B, 2246 0x3001, 0x3001, 2247 0xFE10, 0xFE11, 2248 0xFE50, 0xFE51, 2249 0xFF0C, 0xFF0C, 2250 0xFF64, 0xFF64).freeze(); 2251 2252// private static final UnicodeSet otherGroupingSeparators = new UnicodeSet( 2253// //"[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]" 2254// 0x0020, 0x0020, 2255// 0x0027, 0x0027, 2256// 0x00A0, 0x00A0, 2257// 0x066C, 0x066C, 2258// 0x2000, 0x200A, 2259// 0x2018, 0x2019, 2260// 0x202F, 0x202F, 2261// 0x205F, 0x205F, 2262// 0x3000, 0x3000, 2263// 0xFF07, 0xFF07).freeze(); 2264 2265 private static final UnicodeSet strictDotEquivalents = new UnicodeSet( 2266 //"[.\u2024\uFE52\uFF0E\uFF61]" 2267 0x002E, 0x002E, 2268 0x2024, 0x2024, 2269 0xFE52, 0xFE52, 2270 0xFF0E, 0xFF0E, 2271 0xFF61, 0xFF61).freeze(); 2272 2273 private static final UnicodeSet strictCommaEquivalents = new UnicodeSet( 2274 //"[,\u066B\uFE10\uFE50\uFF0C]" 2275 0x002C, 0x002C, 2276 0x066B, 0x066B, 2277 0xFE10, 0xFE10, 2278 0xFE50, 0xFE50, 2279 0xFF0C, 0xFF0C).freeze(); 2280 2281// private static final UnicodeSet strictOtherGroupingSeparators = new UnicodeSet( 2282// //"[\\ '\u00A0\u066C\u2000-\u200A\u2018\u2019\u202F\u205F\u3000\uFF07]" 2283// 0x0020, 0x0020, 2284// 0x0027, 0x0027, 2285// 0x00A0, 0x00A0, 2286// 0x066C, 0x066C, 2287// 0x2000, 0x200A, 2288// 0x2018, 0x2019, 2289// 0x202F, 0x202F, 2290// 0x205F, 0x205F, 2291// 0x3000, 0x3000, 2292// 0xFF07, 0xFF07).freeze(); 2293 2294 private static final UnicodeSet defaultGroupingSeparators = 2295 // new UnicodeSet(dotEquivalents).addAll(commaEquivalents) 2296 // .addAll(otherGroupingSeparators).freeze(); 2297 new UnicodeSet( 2298 0x0020, 0x0020, 2299 0x0027, 0x0027, 2300 0x002C, 0x002C, 2301 0x002E, 0x002E, 2302 0x00A0, 0x00A0, 2303 0x060C, 0x060C, 2304 0x066B, 0x066C, 2305 0x2000, 0x200A, 2306 0x2018, 0x2019, 2307 0x2024, 0x2024, 2308 0x202F, 0x202F, 2309 0x205F, 0x205F, 2310 0x3000, 0x3002, 2311 0xFE10, 0xFE12, 2312 0xFE50, 0xFE52, 2313 0xFF07, 0xFF07, 2314 0xFF0C, 0xFF0C, 2315 0xFF0E, 0xFF0E, 2316 0xFF61, 0xFF61, 2317 0xFF64, 0xFF64).freeze(); 2318 2319 private static final UnicodeSet strictDefaultGroupingSeparators = 2320 // new UnicodeSet(strictDotEquivalents).addAll(strictCommaEquivalents) 2321 // .addAll(strictOtherGroupingSeparators).freeze(); 2322 new UnicodeSet( 2323 0x0020, 0x0020, 2324 0x0027, 0x0027, 2325 0x002C, 0x002C, 2326 0x002E, 0x002E, 2327 0x00A0, 0x00A0, 2328 0x066B, 0x066C, 2329 0x2000, 0x200A, 2330 0x2018, 0x2019, 2331 0x2024, 0x2024, 2332 0x202F, 0x202F, 2333 0x205F, 0x205F, 2334 0x3000, 0x3000, 2335 0xFE10, 0xFE10, 2336 0xFE50, 0xFE50, 2337 0xFE52, 0xFE52, 2338 0xFF07, 0xFF07, 2339 0xFF0C, 0xFF0C, 2340 0xFF0E, 0xFF0E, 2341 0xFF61, 0xFF61).freeze(); 2342 2343 static final UnicodeSet minusSigns = 2344 new UnicodeSet( 2345 0x002D, 0x002D, 2346 0x207B, 0x207B, 2347 0x208B, 0x208B, 2348 0x2212, 0x2212, 2349 0x2796, 0x2796, 2350 0xFE63, 0xFE63, 2351 0xFF0D, 0xFF0D).freeze(); 2352 2353 static final UnicodeSet plusSigns = 2354 new UnicodeSet( 2355 0x002B, 0x002B, 2356 0x207A, 0x207A, 2357 0x208A, 0x208A, 2358 0x2795, 0x2795, 2359 0xFB29, 0xFB29, 2360 0xFE62, 0xFE62, 2361 0xFF0B, 0xFF0B).freeze(); 2362 2363 // equivalent grouping and decimal support 2364 static final boolean skipExtendedSeparatorParsing = ICUConfig.get( 2365 "android.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", "false") 2366 .equals("true"); 2367 2368 // allow control of requiring a matching decimal point when parsing 2369 boolean parseRequireDecimalPoint = false; 2370 2371 // When parsing a number with big exponential value, it requires to transform the 2372 // value into a string representation to construct BigInteger instance. We want to 2373 // set the maximum size because it can easily trigger OutOfMemoryException. 2374 // PARSE_MAX_EXPONENT is currently set to 1000 (See getParseMaxDigits()), 2375 // which is much bigger than MAX_VALUE of Double ( See the problem reported by ticket#5698 2376 private int PARSE_MAX_EXPONENT = 1000; 2377 2378 /** 2379 * Parses the given text into a number. The text is parsed beginning at parsePosition, 2380 * until an unparseable character is seen. 2381 * 2382 * @param text the string to parse. 2383 * @param parsePosition the position at which to being parsing. Upon return, the first 2384 * unparseable character. 2385 * @param digits the DigitList to set to the parsed value. 2386 * @param status Upon return contains boolean status flags indicating whether the 2387 * value was infinite and whether it was positive. 2388 * @param currency return value for parsed currency, for generic currency parsing 2389 * mode, or null for normal parsing. In generic currency parsing mode, any currency is 2390 * parsed, not just the currency that this formatter is set to. 2391 * @param negPrefix negative prefix pattern 2392 * @param negSuffix negative suffix pattern 2393 * @param posPrefix positive prefix pattern 2394 * @param negSuffix negative suffix pattern 2395 * @param parseComplexCurrency whether it is complex currency parsing or not. 2396 * @param type type of currency to parse against, LONG_NAME only or not. 2397 */ 2398 private final boolean subparse( 2399 String text, ParsePosition parsePosition, DigitList digits, 2400 boolean status[], Currency currency[], String negPrefix, String negSuffix, String posPrefix, 2401 String posSuffix, boolean parseComplexCurrency, int type) { 2402 2403 int position = parsePosition.getIndex(); 2404 int oldStart = parsePosition.getIndex(); 2405 2406 // Match padding before prefix 2407 if (formatWidth > 0 && padPosition == PAD_BEFORE_PREFIX) { 2408 position = skipPadding(text, position); 2409 } 2410 2411 // Match positive and negative prefixes; prefer longest match. 2412 int posMatch = compareAffix(text, position, false, true, posPrefix, parseComplexCurrency, type, currency); 2413 int negMatch = compareAffix(text, position, true, true, negPrefix, parseComplexCurrency, type, currency); 2414 if (posMatch >= 0 && negMatch >= 0) { 2415 if (posMatch > negMatch) { 2416 negMatch = -1; 2417 } else if (negMatch > posMatch) { 2418 posMatch = -1; 2419 } 2420 } 2421 if (posMatch >= 0) { 2422 position += posMatch; 2423 } else if (negMatch >= 0) { 2424 position += negMatch; 2425 } else { 2426 parsePosition.setErrorIndex(position); 2427 return false; 2428 } 2429 2430 // Match padding after prefix 2431 if (formatWidth > 0 && padPosition == PAD_AFTER_PREFIX) { 2432 position = skipPadding(text, position); 2433 } 2434 2435 // process digits or Inf, find decimal position 2436 status[STATUS_INFINITE] = false; 2437 if (text.regionMatches(position, symbols.getInfinity(), 0, 2438 symbols.getInfinity().length())) { 2439 position += symbols.getInfinity().length(); 2440 status[STATUS_INFINITE] = true; 2441 } else { 2442 // We now have a string of digits, possibly with grouping symbols, and decimal 2443 // points. We want to process these into a DigitList. We don't want to put a 2444 // bunch of leading zeros into the DigitList though, so we keep track of the 2445 // location of the decimal point, put only significant digits into the 2446 // DigitList, and adjust the exponent as needed. 2447 2448 digits.decimalAt = digits.count = 0; 2449 String decimal = (currencySignCount == CURRENCY_SIGN_COUNT_ZERO) ? 2450 symbols.getDecimalSeparatorString() : symbols.getMonetaryDecimalSeparatorString(); 2451 String grouping = (currencySignCount == CURRENCY_SIGN_COUNT_ZERO) ? 2452 symbols.getGroupingSeparatorString() : symbols.getMonetaryGroupingSeparatorString(); 2453 2454 String exponentSep = symbols.getExponentSeparator(); 2455 boolean sawDecimal = false; 2456 boolean sawGrouping = false; 2457 boolean sawDigit = false; 2458 long exponent = 0; // Set to the exponent value, if any 2459 2460 // strict parsing 2461 boolean strictParse = isParseStrict(); 2462 boolean strictFail = false; // did we exit with a strict parse failure? 2463 int lastGroup = -1; // where did we last see a grouping separator? 2464 int groupedDigitCount = 0; // tracking count of digits delimited by grouping separator 2465 int gs2 = groupingSize2 == 0 ? groupingSize : groupingSize2; 2466 2467 UnicodeSet decimalEquiv = skipExtendedSeparatorParsing ? UnicodeSet.EMPTY : 2468 getEquivalentDecimals(decimal, strictParse); 2469 UnicodeSet groupEquiv = skipExtendedSeparatorParsing ? UnicodeSet.EMPTY : 2470 (strictParse ? strictDefaultGroupingSeparators : defaultGroupingSeparators); 2471 2472 // We have to track digitCount ourselves, because digits.count will pin when 2473 // the maximum allowable digits is reached. 2474 int digitCount = 0; 2475 2476 int backup = -1; // used for preserving the last confirmed position 2477 int[] parsedDigit = {-1}; // allocates int[1] for parsing a single digit 2478 2479 while (position < text.length()) { 2480 // Check if the sequence at the current position matches a decimal digit 2481 int matchLen = matchesDigit(text, position, parsedDigit); 2482 if (matchLen > 0) { 2483 // matched a digit 2484 // Cancel out backup setting (see grouping handler below) 2485 if (backup != -1) { 2486 if (strictParse) { 2487 // comma followed by digit, so group before comma is a secondary 2488 // group. If there was a group separator before that, the group 2489 // must == the secondary group length, else it can be <= the the 2490 // secondary group length. 2491 if ((lastGroup != -1 && groupedDigitCount != gs2) 2492 || (lastGroup == -1 && groupedDigitCount > gs2)) { 2493 strictFail = true; 2494 break; 2495 } 2496 } 2497 lastGroup = backup; 2498 groupedDigitCount = 0; 2499 } 2500 2501 groupedDigitCount++; 2502 position += matchLen; 2503 backup = -1; 2504 sawDigit = true; 2505 if (parsedDigit[0] == 0 && digits.count == 0) { 2506 // Handle leading zeros 2507 if (!sawDecimal) { 2508 // Ignore leading zeros in integer part of number. 2509 continue; 2510 } 2511 // If we have seen the decimal, but no significant digits yet, 2512 // then we account for leading zeros by decrementing the 2513 // digits.decimalAt into negative values. 2514 --digits.decimalAt; 2515 } else { 2516 ++digitCount; 2517 digits.append((char) (parsedDigit[0] + '0')); 2518 } 2519 continue; 2520 } 2521 2522 // Check if the sequence at the current position matches locale's decimal separator 2523 int decimalStrLen = decimal.length(); 2524 if (text.regionMatches(position, decimal, 0, decimalStrLen)) { 2525 // matched a decimal separator 2526 if (strictParse) { 2527 if (backup != -1 || 2528 (lastGroup != -1 && groupedDigitCount != groupingSize)) { 2529 strictFail = true; 2530 break; 2531 } 2532 } 2533 2534 // If we're only parsing integers, or if we ALREADY saw the decimal, 2535 // then don't parse this one. 2536 if (isParseIntegerOnly() || sawDecimal) { 2537 break; 2538 } 2539 2540 digits.decimalAt = digitCount; // Not digits.count! 2541 sawDecimal = true; 2542 position += decimalStrLen; 2543 continue; 2544 } 2545 2546 if (isGroupingUsed()) { 2547 // Check if the sequence at the current position matches locale's grouping separator 2548 int groupingStrLen = grouping.length(); 2549 if (text.regionMatches(position, grouping, 0, groupingStrLen)) { 2550 if (sawDecimal) { 2551 break; 2552 } 2553 2554 if (strictParse) { 2555 if ((!sawDigit || backup != -1)) { 2556 // leading group, or two group separators in a row 2557 strictFail = true; 2558 break; 2559 } 2560 } 2561 2562 // Ignore grouping characters, if we are using them, but require that 2563 // they be followed by a digit. Otherwise we backup and reprocess 2564 // them. 2565 backup = position; 2566 position += groupingStrLen; 2567 sawGrouping = true; 2568 continue; 2569 } 2570 } 2571 2572 // Check if the code point at the current position matches one of decimal/grouping equivalent group chars 2573 int cp = text.codePointAt(position); 2574 if (!sawDecimal && decimalEquiv.contains(cp)) { 2575 // matched a decimal separator 2576 if (strictParse) { 2577 if (backup != -1 || 2578 (lastGroup != -1 && groupedDigitCount != groupingSize)) { 2579 strictFail = true; 2580 break; 2581 } 2582 } 2583 2584 // If we're only parsing integers, or if we ALREADY saw the decimal, 2585 // then don't parse this one. 2586 if (isParseIntegerOnly()) { 2587 break; 2588 } 2589 2590 digits.decimalAt = digitCount; // Not digits.count! 2591 2592 // Once we see a decimal separator character, we only accept that 2593 // decimal separator character from then on. 2594 decimal = String.valueOf(Character.toChars(cp)); 2595 2596 sawDecimal = true; 2597 position += Character.charCount(cp); 2598 continue; 2599 } 2600 2601 if (isGroupingUsed() && !sawGrouping && groupEquiv.contains(cp)) { 2602 // matched a grouping separator 2603 if (sawDecimal) { 2604 break; 2605 } 2606 2607 if (strictParse) { 2608 if ((!sawDigit || backup != -1)) { 2609 // leading group, or two group separators in a row 2610 strictFail = true; 2611 break; 2612 } 2613 } 2614 2615 // Once we see a grouping character, we only accept that grouping 2616 // character from then on. 2617 grouping = String.valueOf(Character.toChars(cp)); 2618 2619 // Ignore grouping characters, if we are using them, but require that 2620 // they be followed by a digit. Otherwise we backup and reprocess 2621 // them. 2622 backup = position; 2623 position += Character.charCount(cp); 2624 sawGrouping = true; 2625 continue; 2626 } 2627 2628 // Check if the sequence at the current position matches locale's exponent separator 2629 int exponentSepStrLen = exponentSep.length(); 2630 if (text.regionMatches(true, position, exponentSep, 0, exponentSepStrLen)) { 2631 // parse sign, if present 2632 boolean negExp = false; 2633 int pos = position + exponentSep.length(); 2634 if (pos < text.length()) { 2635 String plusSign = symbols.getPlusSignString(); 2636 String minusSign = symbols.getMinusSignString(); 2637 if (text.regionMatches(pos, plusSign, 0, plusSign.length())) { 2638 pos += plusSign.length(); 2639 } else if (text.regionMatches(pos, minusSign, 0, minusSign.length())) { 2640 pos += minusSign.length(); 2641 negExp = true; 2642 } 2643 } 2644 2645 DigitList exponentDigits = new DigitList(); 2646 exponentDigits.count = 0; 2647 while (pos < text.length()) { 2648 int digitMatchLen = matchesDigit(text, pos, parsedDigit); 2649 if (digitMatchLen > 0) { 2650 exponentDigits.append((char) (parsedDigit[0] + '0')); 2651 pos += digitMatchLen; 2652 } else { 2653 break; 2654 } 2655 } 2656 2657 if (exponentDigits.count > 0) { 2658 // defer strict parse until we know we have a bona-fide exponent 2659 if (strictParse && sawGrouping) { 2660 strictFail = true; 2661 break; 2662 } 2663 2664 // Quick overflow check for exponential part. Actual limit check 2665 // will be done later in this code. 2666 if (exponentDigits.count > 10 /* maximum decimal digits for int */) { 2667 if (negExp) { 2668 // set underflow flag 2669 status[STATUS_UNDERFLOW] = true; 2670 } else { 2671 // set infinite flag 2672 status[STATUS_INFINITE] = true; 2673 } 2674 } else { 2675 exponentDigits.decimalAt = exponentDigits.count; 2676 exponent = exponentDigits.getLong(); 2677 if (negExp) { 2678 exponent = -exponent; 2679 } 2680 } 2681 position = pos; // Advance past the exponent 2682 } 2683 2684 break; // Whether we fail or succeed, we exit this loop 2685 } 2686 2687 // All other cases, stop parsing 2688 break; 2689 } 2690 2691 if (digits.decimalAt == 0 && isDecimalPatternMatchRequired()) { 2692 if (this.formatPattern.indexOf(decimal) != -1) { 2693 parsePosition.setIndex(oldStart); 2694 parsePosition.setErrorIndex(position); 2695 return false; 2696 } 2697 } 2698 2699 if (backup != -1) 2700 position = backup; 2701 2702 // If there was no decimal point we have an integer 2703 if (!sawDecimal) { 2704 digits.decimalAt = digitCount; // Not digits.count! 2705 } 2706 2707 // check for strict parse errors 2708 if (strictParse && !sawDecimal) { 2709 if (lastGroup != -1 && groupedDigitCount != groupingSize) { 2710 strictFail = true; 2711 } 2712 } 2713 if (strictFail) { 2714 // only set with strictParse and a leading zero error leading zeros are an 2715 // error with strict parsing except immediately before nondigit (except 2716 // group separator followed by digit), or end of text. 2717 2718 parsePosition.setIndex(oldStart); 2719 parsePosition.setErrorIndex(position); 2720 return false; 2721 } 2722 2723 // Adjust for exponent, if any 2724 exponent += digits.decimalAt; 2725 if (exponent < -getParseMaxDigits()) { 2726 status[STATUS_UNDERFLOW] = true; 2727 } else if (exponent > getParseMaxDigits()) { 2728 status[STATUS_INFINITE] = true; 2729 } else { 2730 digits.decimalAt = (int) exponent; 2731 } 2732 2733 // If none of the text string was recognized. For example, parse "x" with 2734 // pattern "#0.00" (return index and error index both 0) parse "$" with 2735 // pattern "$#0.00". (return index 0 and error index 1). 2736 if (!sawDigit && digitCount == 0) { 2737 parsePosition.setIndex(oldStart); 2738 parsePosition.setErrorIndex(oldStart); 2739 return false; 2740 } 2741 } 2742 2743 // Match padding before suffix 2744 if (formatWidth > 0 && padPosition == PAD_BEFORE_SUFFIX) { 2745 position = skipPadding(text, position); 2746 } 2747 2748 // Match positive and negative suffixes; prefer longest match. 2749 if (posMatch >= 0) { 2750 posMatch = compareAffix(text, position, false, false, posSuffix, parseComplexCurrency, type, currency); 2751 } 2752 if (negMatch >= 0) { 2753 negMatch = compareAffix(text, position, true, false, negSuffix, parseComplexCurrency, type, currency); 2754 } 2755 if (posMatch >= 0 && negMatch >= 0) { 2756 if (posMatch > negMatch) { 2757 negMatch = -1; 2758 } else if (negMatch > posMatch) { 2759 posMatch = -1; 2760 } 2761 } 2762 2763 // Fail if neither or both 2764 if ((posMatch >= 0) == (negMatch >= 0)) { 2765 parsePosition.setErrorIndex(position); 2766 return false; 2767 } 2768 2769 position += (posMatch >= 0 ? posMatch : negMatch); 2770 2771 // Match padding after suffix 2772 if (formatWidth > 0 && padPosition == PAD_AFTER_SUFFIX) { 2773 position = skipPadding(text, position); 2774 } 2775 2776 parsePosition.setIndex(position); 2777 2778 status[STATUS_POSITIVE] = (posMatch >= 0); 2779 2780 if (parsePosition.getIndex() == oldStart) { 2781 parsePosition.setErrorIndex(position); 2782 return false; 2783 } 2784 return true; 2785 } 2786 2787 /** 2788 * Check if the substring at the specified position matches a decimal digit. 2789 * If matched, this method sets the decimal value to <code>decVal</code> and 2790 * returns matched length. 2791 * 2792 * @param str The input string 2793 * @param start The start index 2794 * @param decVal Receives decimal value 2795 * @return Length of match, or 0 if the sequence at the position is not 2796 * a decimal digit. 2797 */ 2798 private int matchesDigit(String str, int start, int[] decVal) { 2799 String[] localeDigits = symbols.getDigitStringsLocal(); 2800 2801 // Check if the sequence at the current position matches locale digits. 2802 for (int i = 0; i < 10; i++) { 2803 int digitStrLen = localeDigits[i].length(); 2804 if (str.regionMatches(start, localeDigits[i], 0, digitStrLen)) { 2805 decVal[0] = i; 2806 return digitStrLen; 2807 } 2808 } 2809 2810 // If no locale digit match, then check if this is a Unicode digit 2811 int cp = str.codePointAt(start); 2812 decVal[0] = UCharacter.digit(cp, 10); 2813 if (decVal[0] >= 0) { 2814 return Character.charCount(cp); 2815 } 2816 2817 return 0; 2818 } 2819 2820 /** 2821 * Returns a set of characters equivalent to the given desimal separator used for 2822 * parsing number. This method may return an empty set. 2823 */ 2824 private UnicodeSet getEquivalentDecimals(String decimal, boolean strictParse) { 2825 UnicodeSet equivSet = UnicodeSet.EMPTY; 2826 if (strictParse) { 2827 if (strictDotEquivalents.contains(decimal)) { 2828 equivSet = strictDotEquivalents; 2829 } else if (strictCommaEquivalents.contains(decimal)) { 2830 equivSet = strictCommaEquivalents; 2831 } 2832 } else { 2833 if (dotEquivalents.contains(decimal)) { 2834 equivSet = dotEquivalents; 2835 } else if (commaEquivalents.contains(decimal)) { 2836 equivSet = commaEquivalents; 2837 } 2838 } 2839 return equivSet; 2840 } 2841 2842 /** 2843 * Starting at position, advance past a run of pad characters, if any. Return the 2844 * index of the first character after position that is not a pad character. Result is 2845 * >= position. 2846 */ 2847 private final int skipPadding(String text, int position) { 2848 while (position < text.length() && text.charAt(position) == pad) { 2849 ++position; 2850 } 2851 return position; 2852 } 2853 2854 /** 2855 * Returns the length matched by the given affix, or -1 if none. Runs of white space 2856 * in the affix, match runs of white space in the input. Pattern white space and input 2857 * white space are determined differently; see code. 2858 * 2859 * @param text input text 2860 * @param pos offset into input at which to begin matching 2861 * @param isNegative 2862 * @param isPrefix 2863 * @param affixPat affix pattern used for currency affix comparison 2864 * @param complexCurrencyParsing whether it is currency parsing or not 2865 * @param type compare against currency type, LONG_NAME only or not. 2866 * @param currency return value for parsed currency, for generic currency parsing 2867 * mode, or null for normal parsing. In generic currency parsing mode, any currency 2868 * is parsed, not just the currency that this formatter is set to. 2869 * @return length of input that matches, or -1 if match failure 2870 */ 2871 private int compareAffix(String text, int pos, boolean isNegative, boolean isPrefix, 2872 String affixPat, boolean complexCurrencyParsing, int type, Currency[] currency) { 2873 if (currency != null || currencyChoice != null || (currencySignCount != CURRENCY_SIGN_COUNT_ZERO && complexCurrencyParsing)) { 2874 return compareComplexAffix(affixPat, text, pos, type, currency); 2875 } 2876 if (isPrefix) { 2877 return compareSimpleAffix(isNegative ? negativePrefix : positivePrefix, text, pos); 2878 } else { 2879 return compareSimpleAffix(isNegative ? negativeSuffix : positiveSuffix, text, pos); 2880 } 2881 2882 } 2883 2884 /** 2885 * Check for bidi marks: LRM, RLM, ALM 2886 */ 2887 private static boolean isBidiMark(int c) { 2888 return (c==0x200E || c==0x200F || c==0x061C); 2889 } 2890 2891 /** 2892 * Remove bidi marks from affix 2893 */ 2894 private static String trimMarksFromAffix(String affix) { 2895 boolean hasBidiMark = false; 2896 int idx = 0; 2897 for (; idx < affix.length(); idx++) { 2898 if (isBidiMark(affix.charAt(idx))) { 2899 hasBidiMark = true; 2900 break; 2901 } 2902 } 2903 if (!hasBidiMark) { 2904 return affix; 2905 } 2906 2907 StringBuilder buf = new StringBuilder(); 2908 buf.append(affix, 0, idx); 2909 idx++; // skip the first Bidi mark 2910 for (; idx < affix.length(); idx++) { 2911 char c = affix.charAt(idx); 2912 if (!isBidiMark(c)) { 2913 buf.append(c); 2914 } 2915 } 2916 2917 return buf.toString(); 2918 } 2919 2920 /** 2921 * Return the length matched by the given affix, or -1 if none. Runs of white space in 2922 * the affix, match runs of white space in the input. Pattern white space and input 2923 * white space are determined differently; see code. 2924 * 2925 * @param affix pattern string, taken as a literal 2926 * @param input input text 2927 * @param pos offset into input at which to begin matching 2928 * @return length of input that matches, or -1 if match failure 2929 */ 2930 private static int compareSimpleAffix(String affix, String input, int pos) { 2931 int start = pos; 2932 // Affixes here might consist of sign, currency symbol and related spacing, etc. 2933 // For more efficiency we should keep lazily-created trimmed affixes around in 2934 // instance variables instead of trimming each time they are used (the next step). 2935 String trimmedAffix = (affix.length() > 1)? trimMarksFromAffix(affix): affix; 2936 for (int i = 0; i < trimmedAffix.length();) { 2937 int c = UTF16.charAt(trimmedAffix, i); 2938 int len = UTF16.getCharCount(c); 2939 if (PatternProps.isWhiteSpace(c)) { 2940 // We may have a pattern like: \u200F and input text like: \u200F Note 2941 // that U+200F and U+0020 are Pattern_White_Space but only U+0020 is 2942 // UWhiteSpace. So we have to first do a direct match of the run of RULE 2943 // whitespace in the pattern, then match any extra characters. 2944 boolean literalMatch = false; 2945 while (pos < input.length()) { 2946 int ic = UTF16.charAt(input, pos); 2947 if (ic == c) { 2948 literalMatch = true; 2949 i += len; 2950 pos += len; 2951 if (i == trimmedAffix.length()) { 2952 break; 2953 } 2954 c = UTF16.charAt(trimmedAffix, i); 2955 len = UTF16.getCharCount(c); 2956 if (!PatternProps.isWhiteSpace(c)) { 2957 break; 2958 } 2959 } else if (isBidiMark(ic)) { 2960 pos++; // just skip over this input text 2961 } else { 2962 break; 2963 } 2964 } 2965 2966 // Advance over run in trimmedAffix 2967 i = skipPatternWhiteSpace(trimmedAffix, i); 2968 2969 // Advance over run in input text. Must see at least one white space char 2970 // in input, unless we've already matched some characters literally. 2971 int s = pos; 2972 pos = skipUWhiteSpace(input, pos); 2973 if (pos == s && !literalMatch) { 2974 return -1; 2975 } 2976 // If we skip UWhiteSpace in the input text, we need to skip it in the 2977 // pattern. Otherwise, the previous lines may have skipped over text 2978 // (such as U+00A0) that is also in the trimmedAffix. 2979 i = skipUWhiteSpace(trimmedAffix, i); 2980 } else { 2981 boolean match = false; 2982 while (pos < input.length()) { 2983 int ic = UTF16.charAt(input, pos); 2984 if (!match && equalWithSignCompatibility(ic, c)) { 2985 i += len; 2986 pos += len; 2987 match = true; 2988 } else if (isBidiMark(ic)) { 2989 pos++; // just skip over this input text 2990 } else { 2991 break; 2992 } 2993 } 2994 if (!match) { 2995 return -1; 2996 } 2997 } 2998 } 2999 return pos - start; 3000 } 3001 3002 private static boolean equalWithSignCompatibility(int lhs, int rhs) { 3003 return lhs == rhs 3004 || (minusSigns.contains(lhs) && minusSigns.contains(rhs)) 3005 || (plusSigns.contains(lhs) && plusSigns.contains(rhs)); 3006 } 3007 3008 /** 3009 * Skips over a run of zero or more Pattern_White_Space characters at pos in text. 3010 */ 3011 private static int skipPatternWhiteSpace(String text, int pos) { 3012 while (pos < text.length()) { 3013 int c = UTF16.charAt(text, pos); 3014 if (!PatternProps.isWhiteSpace(c)) { 3015 break; 3016 } 3017 pos += UTF16.getCharCount(c); 3018 } 3019 return pos; 3020 } 3021 3022 /** 3023 * Skips over a run of zero or more isUWhiteSpace() characters at pos in text. 3024 */ 3025 private static int skipUWhiteSpace(String text, int pos) { 3026 while (pos < text.length()) { 3027 int c = UTF16.charAt(text, pos); 3028 if (!UCharacter.isUWhiteSpace(c)) { 3029 break; 3030 } 3031 pos += UTF16.getCharCount(c); 3032 } 3033 return pos; 3034 } 3035 3036 /** 3037 * Skips over a run of zero or more bidi marks at pos in text. 3038 */ 3039 private static int skipBidiMarks(String text, int pos) { 3040 while (pos < text.length()) { 3041 int c = UTF16.charAt(text, pos); 3042 if (!isBidiMark(c)) { 3043 break; 3044 } 3045 pos += UTF16.getCharCount(c); 3046 } 3047 return pos; 3048 } 3049 3050 /** 3051 * Returns the length matched by the given affix, or -1 if none. 3052 * 3053 * @param affixPat pattern string 3054 * @param text input text 3055 * @param pos offset into input at which to begin matching 3056 * @param type parse against currency type, LONG_NAME only or not. 3057 * @param currency return value for parsed currency, for generic 3058 * currency parsing mode, or null for normal parsing. In generic 3059 * currency parsing mode, any currency is parsed, not just the 3060 * currency that this formatter is set to. 3061 * @return position after the matched text, or -1 if match failure 3062 */ 3063 private int compareComplexAffix(String affixPat, String text, int pos, int type, 3064 Currency[] currency) { 3065 int start = pos; 3066 for (int i = 0; i < affixPat.length() && pos >= 0;) { 3067 char c = affixPat.charAt(i++); 3068 if (c == QUOTE) { 3069 for (;;) { 3070 int j = affixPat.indexOf(QUOTE, i); 3071 if (j == i) { 3072 pos = match(text, pos, QUOTE); 3073 i = j + 1; 3074 break; 3075 } else if (j > i) { 3076 pos = match(text, pos, affixPat.substring(i, j)); 3077 i = j + 1; 3078 if (i < affixPat.length() && affixPat.charAt(i) == QUOTE) { 3079 pos = match(text, pos, QUOTE); 3080 ++i; 3081 // loop again 3082 } else { 3083 break; 3084 } 3085 } else { 3086 // Unterminated quote; should be caught by apply 3087 // pattern. 3088 throw new RuntimeException(); 3089 } 3090 } 3091 continue; 3092 } 3093 3094 String affix = null; 3095 3096 switch (c) { 3097 case CURRENCY_SIGN: 3098 // since the currency names in choice format is saved the same way as 3099 // other currency names, do not need to do currency choice parsing here. 3100 // the general currency parsing parse against all names, including names 3101 // in choice format. assert(currency != null || (getCurrency() != null && 3102 // currencyChoice != null)); 3103 boolean intl = i < affixPat.length() && affixPat.charAt(i) == CURRENCY_SIGN; 3104 if (intl) { 3105 ++i; 3106 } 3107 boolean plural = i < affixPat.length() && affixPat.charAt(i) == CURRENCY_SIGN; 3108 if (plural) { 3109 ++i; 3110 intl = false; 3111 } 3112 // Parse generic currency -- anything for which we have a display name, or 3113 // any 3-letter ISO code. Try to parse display name for our locale; first 3114 // determine our locale. TODO: use locale in CurrencyPluralInfo 3115 ULocale uloc = getLocale(ULocale.VALID_LOCALE); 3116 if (uloc == null) { 3117 // applyPattern has been called; use the symbols 3118 uloc = symbols.getLocale(ULocale.VALID_LOCALE); 3119 } 3120 // Delegate parse of display name => ISO code to Currency 3121 ParsePosition ppos = new ParsePosition(pos); 3122 // using Currency.parse to handle mixed style parsing. 3123 String iso = Currency.parse(uloc, text, type, ppos); 3124 3125 // If parse succeeds, populate currency[0] 3126 if (iso != null) { 3127 if (currency != null) { 3128 currency[0] = Currency.getInstance(iso); 3129 } else { 3130 // The formatter is currency-style but the client has not requested 3131 // the value of the parsed currency. In this case, if that value does 3132 // not match the formatter's current value, then the parse fails. 3133 Currency effectiveCurr = getEffectiveCurrency(); 3134 if (iso.compareTo(effectiveCurr.getCurrencyCode()) != 0) { 3135 pos = -1; 3136 continue; 3137 } 3138 } 3139 pos = ppos.getIndex(); 3140 } else { 3141 pos = -1; 3142 } 3143 continue; 3144 case PATTERN_PERCENT: 3145 affix = symbols.getPercentString(); 3146 break; 3147 case PATTERN_PER_MILLE: 3148 affix = symbols.getPerMillString(); 3149 break; 3150 case PATTERN_PLUS_SIGN: 3151 affix = symbols.getPlusSignString(); 3152 break; 3153 case PATTERN_MINUS_SIGN: 3154 affix = symbols.getMinusSignString(); 3155 break; 3156 default: 3157 // fall through to affix != null test, which will fail 3158 break; 3159 } 3160 3161 if (affix != null) { 3162 pos = match(text, pos, affix); 3163 continue; 3164 } 3165 3166 pos = match(text, pos, c); 3167 if (PatternProps.isWhiteSpace(c)) { 3168 i = skipPatternWhiteSpace(affixPat, i); 3169 } 3170 } 3171 3172 return pos - start; 3173 } 3174 3175 /** 3176 * Matches a single character at text[pos] and return the index of the next character 3177 * upon success. Return -1 on failure. If ch is a Pattern_White_Space then match a run of 3178 * white space in text. 3179 */ 3180 static final int match(String text, int pos, int ch) { 3181 if (pos < 0 || pos >= text.length()) { 3182 return -1; 3183 } 3184 pos = skipBidiMarks(text, pos); 3185 if (PatternProps.isWhiteSpace(ch)) { 3186 // Advance over run of white space in input text 3187 // Must see at least one white space char in input 3188 int s = pos; 3189 pos = skipPatternWhiteSpace(text, pos); 3190 if (pos == s) { 3191 return -1; 3192 } 3193 return pos; 3194 } 3195 if (pos >= text.length() || UTF16.charAt(text, pos) != ch) { 3196 return -1; 3197 } 3198 pos = skipBidiMarks(text, pos + UTF16.getCharCount(ch)); 3199 return pos; 3200 } 3201 3202 /** 3203 * Matches a string at text[pos] and return the index of the next character upon 3204 * success. Return -1 on failure. Match a run of white space in str with a run of 3205 * white space in text. 3206 */ 3207 static final int match(String text, int pos, String str) { 3208 for (int i = 0; i < str.length() && pos >= 0;) { 3209 int ch = UTF16.charAt(str, i); 3210 i += UTF16.getCharCount(ch); 3211 if (isBidiMark(ch)) { 3212 continue; 3213 } 3214 pos = match(text, pos, ch); 3215 if (PatternProps.isWhiteSpace(ch)) { 3216 i = skipPatternWhiteSpace(str, i); 3217 } 3218 } 3219 return pos; 3220 } 3221 3222 /** 3223 * Returns a copy of the decimal format symbols used by this format. 3224 * 3225 * @return desired DecimalFormatSymbols 3226 * @see DecimalFormatSymbols 3227 */ 3228 public DecimalFormatSymbols getDecimalFormatSymbols() { 3229 try { 3230 // don't allow multiple references 3231 return (DecimalFormatSymbols) symbols.clone(); 3232 } catch (Exception foo) { 3233 return null; // should never happen 3234 } 3235 } 3236 3237 /** 3238 * Sets the decimal format symbols used by this format. The format uses a copy of the 3239 * provided symbols. 3240 * 3241 * @param newSymbols desired DecimalFormatSymbols 3242 * @see DecimalFormatSymbols 3243 */ 3244 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { 3245 symbols = (DecimalFormatSymbols) newSymbols.clone(); 3246 setCurrencyForSymbols(); 3247 expandAffixes(null); 3248 } 3249 3250 /** 3251 * Update the currency object to match the symbols. This method is used only when the 3252 * caller has passed in a symbols object that may not be the default object for its 3253 * locale. 3254 */ 3255 private void setCurrencyForSymbols() { 3256 3257 // Bug 4212072 Update the affix strings according to symbols in order to keep the 3258 // affix strings up to date. [Richard/GCL] 3259 3260 // With the introduction of the Currency object, the currency symbols in the DFS 3261 // object are ignored. For backward compatibility, we check any explicitly set DFS 3262 // object. If it is a default symbols object for its locale, we change the 3263 // currency object to one for that locale. If it is custom, we set the currency to 3264 // null. 3265 DecimalFormatSymbols def = new DecimalFormatSymbols(symbols.getULocale()); 3266 3267 if (symbols.getCurrencySymbol().equals(def.getCurrencySymbol()) 3268 && symbols.getInternationalCurrencySymbol() 3269 .equals(def.getInternationalCurrencySymbol())) { 3270 setCurrency(Currency.getInstance(symbols.getULocale())); 3271 } else { 3272 setCurrency(null); 3273 } 3274 } 3275 3276 /** 3277 * Returns the positive prefix. 3278 * 3279 * <p>Examples: +123, $123, sFr123 3280 * @return the prefix 3281 */ 3282 public String getPositivePrefix() { 3283 return positivePrefix; 3284 } 3285 3286 /** 3287 * Sets the positive prefix. 3288 * 3289 * <p>Examples: +123, $123, sFr123 3290 * @param newValue the prefix 3291 */ 3292 public void setPositivePrefix(String newValue) { 3293 positivePrefix = newValue; 3294 posPrefixPattern = null; 3295 } 3296 3297 /** 3298 * Returns the negative prefix. 3299 * 3300 * <p>Examples: -123, ($123) (with negative suffix), sFr-123 3301 * 3302 * @return the prefix 3303 */ 3304 public String getNegativePrefix() { 3305 return negativePrefix; 3306 } 3307 3308 /** 3309 * Sets the negative prefix. 3310 * 3311 * <p>Examples: -123, ($123) (with negative suffix), sFr-123 3312 * @param newValue the prefix 3313 */ 3314 public void setNegativePrefix(String newValue) { 3315 negativePrefix = newValue; 3316 negPrefixPattern = null; 3317 } 3318 3319 /** 3320 * Returns the positive suffix. 3321 * 3322 * <p>Example: 123% 3323 * 3324 * @return the suffix 3325 */ 3326 public String getPositiveSuffix() { 3327 return positiveSuffix; 3328 } 3329 3330 /** 3331 * Sets the positive suffix. 3332 * 3333 * <p>Example: 123% 3334 * @param newValue the suffix 3335 */ 3336 public void setPositiveSuffix(String newValue) { 3337 positiveSuffix = newValue; 3338 posSuffixPattern = null; 3339 } 3340 3341 /** 3342 * Returns the negative suffix. 3343 * 3344 * <p>Examples: -123%, ($123) (with positive suffixes) 3345 * 3346 * @return the suffix 3347 */ 3348 public String getNegativeSuffix() { 3349 return negativeSuffix; 3350 } 3351 3352 /** 3353 * Sets the positive suffix. 3354 * 3355 * <p>Examples: 123% 3356 * @param newValue the suffix 3357 */ 3358 public void setNegativeSuffix(String newValue) { 3359 negativeSuffix = newValue; 3360 negSuffixPattern = null; 3361 } 3362 3363 /** 3364 * Returns the multiplier for use in percent, permill, etc. For a percentage, set the 3365 * suffixes to have "%" and the multiplier to be 100. (For Arabic, use arabic percent 3366 * symbol). For a permill, set the suffixes to have "\u2031" and the multiplier to be 3367 * 1000. 3368 * 3369 * <p>Examples: with 100, 1.23 -> "123", and "123" -> 1.23 3370 * 3371 * @return the multiplier 3372 */ 3373 public int getMultiplier() { 3374 return multiplier; 3375 } 3376 3377 /** 3378 * Sets the multiplier for use in percent, permill, etc. For a percentage, set the 3379 * suffixes to have "%" and the multiplier to be 100. (For Arabic, use arabic percent 3380 * symbol). For a permill, set the suffixes to have "\u2031" and the multiplier to be 3381 * 1000. 3382 * 3383 * <p>Examples: with 100, 1.23 -> "123", and "123" -> 1.23 3384 * 3385 * @param newValue the multiplier 3386 */ 3387 public void setMultiplier(int newValue) { 3388 if (newValue == 0) { 3389 throw new IllegalArgumentException("Bad multiplier: " + newValue); 3390 } 3391 multiplier = newValue; 3392 } 3393 3394 /** 3395 * <strong>[icu]</strong> Returns the rounding increment. 3396 * 3397 * @return A positive rounding increment, or <code>null</code> if a custom rounding 3398 * increment is not in effect. 3399 * @see #setRoundingIncrement 3400 * @see #getRoundingMode 3401 * @see #setRoundingMode 3402 */ 3403 public java.math.BigDecimal getRoundingIncrement() { 3404 if (roundingIncrementICU == null) 3405 return null; 3406 return roundingIncrementICU.toBigDecimal(); 3407 } 3408 3409 /** 3410 * <strong>[icu]</strong> Sets the rounding increment. In the absence of a rounding increment, numbers 3411 * will be rounded to the number of digits displayed. 3412 * 3413 * @param newValue A positive rounding increment, or <code>null</code> or 3414 * <code>BigDecimal(0.0)</code> to use the default rounding increment. 3415 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0 3416 * @see #getRoundingIncrement 3417 * @see #getRoundingMode 3418 * @see #setRoundingMode 3419 */ 3420 public void setRoundingIncrement(java.math.BigDecimal newValue) { 3421 if (newValue == null) { 3422 setRoundingIncrement((BigDecimal) null); 3423 } else { 3424 setRoundingIncrement(new BigDecimal(newValue)); 3425 } 3426 } 3427 3428 /** 3429 * <strong>[icu]</strong> Sets the rounding increment. In the absence of a rounding increment, numbers 3430 * will be rounded to the number of digits displayed. 3431 * 3432 * @param newValue A positive rounding increment, or <code>null</code> or 3433 * <code>BigDecimal(0.0)</code> to use the default rounding increment. 3434 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0 3435 * @see #getRoundingIncrement 3436 * @see #getRoundingMode 3437 * @see #setRoundingMode 3438 */ 3439 public void setRoundingIncrement(BigDecimal newValue) { 3440 int i = newValue == null ? 0 : newValue.compareTo(BigDecimal.ZERO); 3441 if (i < 0) { 3442 throw new IllegalArgumentException("Illegal rounding increment"); 3443 } 3444 if (i == 0) { 3445 setInternalRoundingIncrement(null); 3446 } else { 3447 setInternalRoundingIncrement(newValue); 3448 } 3449 resetActualRounding(); 3450 } 3451 3452 /** 3453 * <strong>[icu]</strong> Sets the rounding increment. In the absence of a rounding increment, numbers 3454 * will be rounded to the number of digits displayed. 3455 * 3456 * @param newValue A positive rounding increment, or 0.0 to use the default 3457 * rounding increment. 3458 * @throws IllegalArgumentException if <code>newValue</code> is < 0.0 3459 * @see #getRoundingIncrement 3460 * @see #getRoundingMode 3461 * @see #setRoundingMode 3462 */ 3463 public void setRoundingIncrement(double newValue) { 3464 if (newValue < 0.0) { 3465 throw new IllegalArgumentException("Illegal rounding increment"); 3466 } 3467 if (newValue == 0.0d) { 3468 setInternalRoundingIncrement((BigDecimal) null); 3469 } else { 3470 // Should use BigDecimal#valueOf(double) instead of constructor 3471 // to avoid the double precision problem. 3472 setInternalRoundingIncrement(BigDecimal.valueOf(newValue)); 3473 } 3474 resetActualRounding(); 3475 } 3476 3477 /** 3478 * Returns the rounding mode. 3479 * 3480 * @return A rounding mode, between <code>BigDecimal.ROUND_UP</code> and 3481 * <code>BigDecimal.ROUND_UNNECESSARY</code>. 3482 * @see #setRoundingIncrement 3483 * @see #getRoundingIncrement 3484 * @see #setRoundingMode 3485 * @see java.math.BigDecimal 3486 */ 3487 @Override 3488 public int getRoundingMode() { 3489 return roundingMode; 3490 } 3491 3492 /** 3493 * Sets the rounding mode. This has no effect unless the rounding increment is greater 3494 * than zero. 3495 * 3496 * @param roundingMode A rounding mode, between <code>BigDecimal.ROUND_UP</code> and 3497 * <code>BigDecimal.ROUND_UNNECESSARY</code>. 3498 * @exception IllegalArgumentException if <code>roundingMode</code> is unrecognized. 3499 * @see #setRoundingIncrement 3500 * @see #getRoundingIncrement 3501 * @see #getRoundingMode 3502 * @see java.math.BigDecimal 3503 */ 3504 @Override 3505 public void setRoundingMode(int roundingMode) { 3506 if (roundingMode < BigDecimal.ROUND_UP || roundingMode > BigDecimal.ROUND_UNNECESSARY) { 3507 throw new IllegalArgumentException("Invalid rounding mode: " + roundingMode); 3508 } 3509 3510 this.roundingMode = roundingMode; 3511 resetActualRounding(); 3512 } 3513 3514 /** 3515 * Returns the width to which the output of <code>format()</code> is padded. The width is 3516 * counted in 16-bit code units. 3517 * 3518 * @return the format width, or zero if no padding is in effect 3519 * @see #setFormatWidth 3520 * @see #getPadCharacter 3521 * @see #setPadCharacter 3522 * @see #getPadPosition 3523 * @see #setPadPosition 3524 */ 3525 public int getFormatWidth() { 3526 return formatWidth; 3527 } 3528 3529 /** 3530 * Sets the width to which the output of <code>format()</code> is 3531 * padded. The width is counted in 16-bit code units. This method 3532 * also controls whether padding is enabled. 3533 * 3534 * @param width the width to which to pad the result of 3535 * <code>format()</code>, or zero to disable padding 3536 * @exception IllegalArgumentException if <code>width</code> is < 0 3537 * @see #getFormatWidth 3538 * @see #getPadCharacter 3539 * @see #setPadCharacter 3540 * @see #getPadPosition 3541 * @see #setPadPosition 3542 */ 3543 public void setFormatWidth(int width) { 3544 if (width < 0) { 3545 throw new IllegalArgumentException("Illegal format width"); 3546 } 3547 formatWidth = width; 3548 } 3549 3550 /** 3551 * <strong>[icu]</strong> Returns the character used to pad to the format width. The default is ' '. 3552 * 3553 * @return the pad character 3554 * @see #setFormatWidth 3555 * @see #getFormatWidth 3556 * @see #setPadCharacter 3557 * @see #getPadPosition 3558 * @see #setPadPosition 3559 */ 3560 public char getPadCharacter() { 3561 return pad; 3562 } 3563 3564 /** 3565 * <strong>[icu]</strong> Sets the character used to pad to the format width. If padding is not 3566 * enabled, then this will take effect if padding is later enabled. 3567 * 3568 * @param padChar the pad character 3569 * @see #setFormatWidth 3570 * @see #getFormatWidth 3571 * @see #getPadCharacter 3572 * @see #getPadPosition 3573 * @see #setPadPosition 3574 */ 3575 public void setPadCharacter(char padChar) { 3576 pad = padChar; 3577 } 3578 3579 /** 3580 * <strong>[icu]</strong> Returns the position at which padding will take place. This is the location at 3581 * which padding will be inserted if the result of <code>format()</code> is shorter 3582 * than the format width. 3583 * 3584 * @return the pad position, one of <code>PAD_BEFORE_PREFIX</code>, 3585 * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or 3586 * <code>PAD_AFTER_SUFFIX</code>. 3587 * @see #setFormatWidth 3588 * @see #getFormatWidth 3589 * @see #setPadCharacter 3590 * @see #getPadCharacter 3591 * @see #setPadPosition 3592 * @see #PAD_BEFORE_PREFIX 3593 * @see #PAD_AFTER_PREFIX 3594 * @see #PAD_BEFORE_SUFFIX 3595 * @see #PAD_AFTER_SUFFIX 3596 */ 3597 public int getPadPosition() { 3598 return padPosition; 3599 } 3600 3601 /** 3602 * <strong>[icu]</strong> Sets the position at which padding will take place. This is the location at 3603 * which padding will be inserted if the result of <code>format()</code> is shorter 3604 * than the format width. This has no effect unless padding is enabled. 3605 * 3606 * @param padPos the pad position, one of <code>PAD_BEFORE_PREFIX</code>, 3607 * <code>PAD_AFTER_PREFIX</code>, <code>PAD_BEFORE_SUFFIX</code>, or 3608 * <code>PAD_AFTER_SUFFIX</code>. 3609 * @exception IllegalArgumentException if the pad position in unrecognized 3610 * @see #setFormatWidth 3611 * @see #getFormatWidth 3612 * @see #setPadCharacter 3613 * @see #getPadCharacter 3614 * @see #getPadPosition 3615 * @see #PAD_BEFORE_PREFIX 3616 * @see #PAD_AFTER_PREFIX 3617 * @see #PAD_BEFORE_SUFFIX 3618 * @see #PAD_AFTER_SUFFIX 3619 */ 3620 public void setPadPosition(int padPos) { 3621 if (padPos < PAD_BEFORE_PREFIX || padPos > PAD_AFTER_SUFFIX) { 3622 throw new IllegalArgumentException("Illegal pad position"); 3623 } 3624 padPosition = padPos; 3625 } 3626 3627 /** 3628 * <strong>[icu]</strong> Returns whether or not scientific notation is used. 3629 * 3630 * @return true if this object formats and parses scientific notation 3631 * @see #setScientificNotation 3632 * @see #getMinimumExponentDigits 3633 * @see #setMinimumExponentDigits 3634 * @see #isExponentSignAlwaysShown 3635 * @see #setExponentSignAlwaysShown 3636 */ 3637 public boolean isScientificNotation() { 3638 return useExponentialNotation; 3639 } 3640 3641 /** 3642 * <strong>[icu]</strong> Sets whether or not scientific notation is used. When scientific notation is 3643 * used, the effective maximum number of integer digits is <= 8. If the maximum number 3644 * of integer digits is set to more than 8, the effective maximum will be 1. This 3645 * allows this call to generate a 'default' scientific number format without 3646 * additional changes. 3647 * 3648 * @param useScientific true if this object formats and parses scientific notation 3649 * @see #isScientificNotation 3650 * @see #getMinimumExponentDigits 3651 * @see #setMinimumExponentDigits 3652 * @see #isExponentSignAlwaysShown 3653 * @see #setExponentSignAlwaysShown 3654 */ 3655 public void setScientificNotation(boolean useScientific) { 3656 useExponentialNotation = useScientific; 3657 } 3658 3659 /** 3660 * <strong>[icu]</strong> Returns the minimum exponent digits that will be shown. 3661 * 3662 * @return the minimum exponent digits that will be shown 3663 * @see #setScientificNotation 3664 * @see #isScientificNotation 3665 * @see #setMinimumExponentDigits 3666 * @see #isExponentSignAlwaysShown 3667 * @see #setExponentSignAlwaysShown 3668 */ 3669 public byte getMinimumExponentDigits() { 3670 return minExponentDigits; 3671 } 3672 3673 /** 3674 * <strong>[icu]</strong> Sets the minimum exponent digits that will be shown. This has no effect 3675 * unless scientific notation is in use. 3676 * 3677 * @param minExpDig a value >= 1 indicating the fewest exponent 3678 * digits that will be shown 3679 * @exception IllegalArgumentException if <code>minExpDig</code> < 1 3680 * @see #setScientificNotation 3681 * @see #isScientificNotation 3682 * @see #getMinimumExponentDigits 3683 * @see #isExponentSignAlwaysShown 3684 * @see #setExponentSignAlwaysShown 3685 */ 3686 public void setMinimumExponentDigits(byte minExpDig) { 3687 if (minExpDig < 1) { 3688 throw new IllegalArgumentException("Exponent digits must be >= 1"); 3689 } 3690 minExponentDigits = minExpDig; 3691 } 3692 3693 /** 3694 * <strong>[icu]</strong> Returns whether the exponent sign is always shown. 3695 * 3696 * @return true if the exponent is always prefixed with either the localized minus 3697 * sign or the localized plus sign, false if only negative exponents are prefixed with 3698 * the localized minus sign. 3699 * @see #setScientificNotation 3700 * @see #isScientificNotation 3701 * @see #setMinimumExponentDigits 3702 * @see #getMinimumExponentDigits 3703 * @see #setExponentSignAlwaysShown 3704 */ 3705 public boolean isExponentSignAlwaysShown() { 3706 return exponentSignAlwaysShown; 3707 } 3708 3709 /** 3710 * <strong>[icu]</strong> Sets whether the exponent sign is always shown. This has no effect unless 3711 * scientific notation is in use. 3712 * 3713 * @param expSignAlways true if the exponent is always prefixed with either the 3714 * localized minus sign or the localized plus sign, false if only negative exponents 3715 * are prefixed with the localized minus sign. 3716 * @see #setScientificNotation 3717 * @see #isScientificNotation 3718 * @see #setMinimumExponentDigits 3719 * @see #getMinimumExponentDigits 3720 * @see #isExponentSignAlwaysShown 3721 */ 3722 public void setExponentSignAlwaysShown(boolean expSignAlways) { 3723 exponentSignAlwaysShown = expSignAlways; 3724 } 3725 3726 /** 3727 * Returns the grouping size. Grouping size is the number of digits between grouping 3728 * separators in the integer portion of a number. For example, in the number 3729 * "123,456.78", the grouping size is 3. 3730 * 3731 * @see #setGroupingSize 3732 * @see NumberFormat#isGroupingUsed 3733 * @see DecimalFormatSymbols#getGroupingSeparator 3734 */ 3735 public int getGroupingSize() { 3736 return groupingSize; 3737 } 3738 3739 /** 3740 * Sets the grouping size. Grouping size is the number of digits between grouping 3741 * separators in the integer portion of a number. For example, in the number 3742 * "123,456.78", the grouping size is 3. 3743 * 3744 * @see #getGroupingSize 3745 * @see NumberFormat#setGroupingUsed 3746 * @see DecimalFormatSymbols#setGroupingSeparator 3747 */ 3748 public void setGroupingSize(int newValue) { 3749 groupingSize = (byte) newValue; 3750 } 3751 3752 /** 3753 * <strong>[icu]</strong> Returns the secondary grouping size. In some locales one grouping interval 3754 * is used for the least significant integer digits (the primary grouping size), and 3755 * another is used for all others (the secondary grouping size). A formatter 3756 * supporting a secondary grouping size will return a positive integer unequal to the 3757 * primary grouping size returned by <code>getGroupingSize()</code>. For example, if 3758 * the primary grouping size is 4, and the secondary grouping size is 2, then the 3759 * number 123456789 formats as "1,23,45,6789", and the pattern appears as "#,##,###0". 3760 * 3761 * @return the secondary grouping size, or a value less than one if there is none 3762 * @see #setSecondaryGroupingSize 3763 * @see NumberFormat#isGroupingUsed 3764 * @see DecimalFormatSymbols#getGroupingSeparator 3765 */ 3766 public int getSecondaryGroupingSize() { 3767 return groupingSize2; 3768 } 3769 3770 /** 3771 * <strong>[icu]</strong> Sets the secondary grouping size. If set to a value less than 1, then 3772 * secondary grouping is turned off, and the primary grouping size is used for all 3773 * intervals, not just the least significant. 3774 * 3775 * @see #getSecondaryGroupingSize 3776 * @see NumberFormat#setGroupingUsed 3777 * @see DecimalFormatSymbols#setGroupingSeparator 3778 */ 3779 public void setSecondaryGroupingSize(int newValue) { 3780 groupingSize2 = (byte) newValue; 3781 } 3782 3783 /** 3784 * <strong>[icu]</strong> Returns the MathContext used by this format. 3785 * 3786 * @return desired MathContext 3787 * @see #getMathContext 3788 */ 3789 public MathContext getMathContextICU() { 3790 return mathContext; 3791 } 3792 3793 /** 3794 * <strong>[icu]</strong> Returns the MathContext used by this format. 3795 * 3796 * @return desired MathContext 3797 * @see #getMathContext 3798 */ 3799 public java.math.MathContext getMathContext() { 3800 try { 3801 // don't allow multiple references 3802 return mathContext == null ? null : new java.math.MathContext(mathContext.getDigits(), 3803 java.math.RoundingMode.valueOf(mathContext.getRoundingMode())); 3804 } catch (Exception foo) { 3805 return null; // should never happen 3806 } 3807 } 3808 3809 /** 3810 * <strong>[icu]</strong> Sets the MathContext used by this format. 3811 * 3812 * @param newValue desired MathContext 3813 * @see #getMathContext 3814 */ 3815 public void setMathContextICU(MathContext newValue) { 3816 mathContext = newValue; 3817 } 3818 3819 /** 3820 * <strong>[icu]</strong> Sets the MathContext used by this format. 3821 * 3822 * @param newValue desired MathContext 3823 * @see #getMathContext 3824 */ 3825 public void setMathContext(java.math.MathContext newValue) { 3826 mathContext = new MathContext(newValue.getPrecision(), MathContext.SCIENTIFIC, false, 3827 (newValue.getRoundingMode()).ordinal()); 3828 } 3829 3830 /** 3831 * Returns the behavior of the decimal separator with integers. (The decimal 3832 * separator will always appear with decimals.) <p> Example: Decimal ON: 12345 -> 3833 * 12345.; OFF: 12345 -> 12345 3834 */ 3835 public boolean isDecimalSeparatorAlwaysShown() { 3836 return decimalSeparatorAlwaysShown; 3837 } 3838 3839 /** 3840 * When decimal match is not required, the input does not have to 3841 * contain a decimal mark when there is a decimal mark specified in the 3842 * pattern. 3843 * @param value true if input must contain a match to decimal mark in pattern 3844 * Default is false. 3845 */ 3846 public void setDecimalPatternMatchRequired(boolean value) { 3847 parseRequireDecimalPoint = value; 3848 } 3849 3850 /** 3851 * <strong>[icu]</strong> Returns whether the input to parsing must contain a decimal mark if there 3852 * is a decimal mark in the pattern. 3853 * @return true if input must contain a match to decimal mark in pattern 3854 */ 3855 public boolean isDecimalPatternMatchRequired() { 3856 return parseRequireDecimalPoint; 3857 } 3858 3859 3860 /** 3861 * Sets the behavior of the decimal separator with integers. (The decimal separator 3862 * will always appear with decimals.) 3863 * 3864 * <p>This only affects formatting, and only where there might be no digits after the 3865 * decimal point, e.g., if true, 3456.00 -> "3,456." if false, 3456.00 -> "3456" This 3866 * is independent of parsing. If you want parsing to stop at the decimal point, use 3867 * setParseIntegerOnly. 3868 * 3869 * <p> 3870 * Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345 3871 */ 3872 public void setDecimalSeparatorAlwaysShown(boolean newValue) { 3873 decimalSeparatorAlwaysShown = newValue; 3874 } 3875 3876 /** 3877 * <strong>[icu]</strong> Returns a copy of the CurrencyPluralInfo used by this format. It might 3878 * return null if the decimal format is not a plural type currency decimal 3879 * format. Plural type currency decimal format means either the pattern in the decimal 3880 * format contains 3 currency signs, or the decimal format is initialized with 3881 * PLURALCURRENCYSTYLE. 3882 * 3883 * @return desired CurrencyPluralInfo 3884 * @see CurrencyPluralInfo 3885 */ 3886 public CurrencyPluralInfo getCurrencyPluralInfo() { 3887 try { 3888 // don't allow multiple references 3889 return currencyPluralInfo == null ? null : 3890 (CurrencyPluralInfo) currencyPluralInfo.clone(); 3891 } catch (Exception foo) { 3892 return null; // should never happen 3893 } 3894 } 3895 3896 /** 3897 * <strong>[icu]</strong> Sets the CurrencyPluralInfo used by this format. The format uses a copy of 3898 * the provided information. 3899 * 3900 * @param newInfo desired CurrencyPluralInfo 3901 * @see CurrencyPluralInfo 3902 */ 3903 public void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) { 3904 currencyPluralInfo = (CurrencyPluralInfo) newInfo.clone(); 3905 isReadyForParsing = false; 3906 } 3907 3908 /** 3909 * Overrides clone. 3910 */ 3911 @Override 3912 public Object clone() { 3913 try { 3914 DecimalFormat other = (DecimalFormat) super.clone(); 3915 other.symbols = (DecimalFormatSymbols) symbols.clone(); 3916 other.digitList = new DigitList(); // fix for JB#5358 3917 if (currencyPluralInfo != null) { 3918 other.currencyPluralInfo = (CurrencyPluralInfo) currencyPluralInfo.clone(); 3919 } 3920 other.attributes = new ArrayList<FieldPosition>(); // #9240 3921 other.currencyUsage = currencyUsage; 3922 3923 // TODO: We need to figure out whether we share a single copy of DigitList by 3924 // multiple cloned copies. format/subformat are designed to use a single 3925 // instance, but parse/subparse implementation is not. 3926 return other; 3927 } catch (Exception e) { 3928 throw new IllegalStateException(); 3929 } 3930 } 3931 3932 /** 3933 * Overrides equals. 3934 */ 3935 @Override 3936 public boolean equals(Object obj) { 3937 if (obj == null) 3938 return false; 3939 if (!super.equals(obj)) 3940 return false; // super does class check 3941 3942 DecimalFormat other = (DecimalFormat) obj; 3943 // Add the comparison of the four new added fields ,they are posPrefixPattern, 3944 // posSuffixPattern, negPrefixPattern, negSuffixPattern. [Richard/GCL] 3945 // following are added to accomodate changes for currency plural format. 3946 return currencySignCount == other.currencySignCount 3947 && (style != NumberFormat.PLURALCURRENCYSTYLE || 3948 equals(posPrefixPattern, other.posPrefixPattern) 3949 && equals(posSuffixPattern, other.posSuffixPattern) 3950 && equals(negPrefixPattern, other.negPrefixPattern) 3951 && equals(negSuffixPattern, other.negSuffixPattern)) 3952 && multiplier == other.multiplier 3953 && groupingSize == other.groupingSize 3954 && groupingSize2 == other.groupingSize2 3955 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown 3956 && useExponentialNotation == other.useExponentialNotation 3957 && (!useExponentialNotation || minExponentDigits == other.minExponentDigits) 3958 && useSignificantDigits == other.useSignificantDigits 3959 && (!useSignificantDigits || minSignificantDigits == other.minSignificantDigits 3960 && maxSignificantDigits == other.maxSignificantDigits) 3961 && symbols.equals(other.symbols) 3962 && Utility.objectEquals(currencyPluralInfo, other.currencyPluralInfo) 3963 && currencyUsage.equals(other.currencyUsage); 3964 } 3965 3966 // method to unquote the strings and compare 3967 private boolean equals(String pat1, String pat2) { 3968 if (pat1 == null || pat2 == null) { 3969 return (pat1 == null && pat2 == null); 3970 } 3971 // fast path 3972 if (pat1.equals(pat2)) { 3973 return true; 3974 } 3975 return unquote(pat1).equals(unquote(pat2)); 3976 } 3977 3978 private String unquote(String pat) { 3979 StringBuilder buf = new StringBuilder(pat.length()); 3980 int i = 0; 3981 while (i < pat.length()) { 3982 char ch = pat.charAt(i++); 3983 if (ch != QUOTE) { 3984 buf.append(ch); 3985 } 3986 } 3987 return buf.toString(); 3988 } 3989 3990 // protected void handleToString(StringBuffer buf) { 3991 // buf.append("\nposPrefixPattern: '" + posPrefixPattern + "'\n"); 3992 // buf.append("positivePrefix: '" + positivePrefix + "'\n"); 3993 // buf.append("posSuffixPattern: '" + posSuffixPattern + "'\n"); 3994 // buf.append("positiveSuffix: '" + positiveSuffix + "'\n"); 3995 // buf.append("negPrefixPattern: '" + 3996 // android.icu.impl.Utility.format1ForSource(negPrefixPattern) + "'\n"); 3997 // buf.append("negativePrefix: '" + 3998 // android.icu.impl.Utility.format1ForSource(negativePrefix) + "'\n"); 3999 // buf.append("negSuffixPattern: '" + negSuffixPattern + "'\n"); 4000 // buf.append("negativeSuffix: '" + negativeSuffix + "'\n"); 4001 // buf.append("multiplier: '" + multiplier + "'\n"); 4002 // buf.append("groupingSize: '" + groupingSize + "'\n"); 4003 // buf.append("groupingSize2: '" + groupingSize2 + "'\n"); 4004 // buf.append("decimalSeparatorAlwaysShown: '" + decimalSeparatorAlwaysShown + "'\n"); 4005 // buf.append("useExponentialNotation: '" + useExponentialNotation + "'\n"); 4006 // buf.append("minExponentDigits: '" + minExponentDigits + "'\n"); 4007 // buf.append("useSignificantDigits: '" + useSignificantDigits + "'\n"); 4008 // buf.append("minSignificantDigits: '" + minSignificantDigits + "'\n"); 4009 // buf.append("maxSignificantDigits: '" + maxSignificantDigits + "'\n"); 4010 // buf.append("symbols: '" + symbols + "'"); 4011 // } 4012 4013 /** 4014 * Overrides hashCode. 4015 */ 4016 @Override 4017 public int hashCode() { 4018 return super.hashCode() * 37 + positivePrefix.hashCode(); 4019 // just enough fields for a reasonable distribution 4020 } 4021 4022 /** 4023 * Synthesizes a pattern string that represents the current state of this Format 4024 * object. 4025 * 4026 * @see #applyPattern 4027 */ 4028 public String toPattern() { 4029 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 4030 // the prefix or suffix pattern might not be defined yet, so they can not be 4031 // synthesized, instead, get them directly. but it might not be the actual 4032 // pattern used in formatting. the actual pattern used in formatting depends 4033 // on the formatted number's plural count. 4034 return formatPattern; 4035 } 4036 return toPattern(false); 4037 } 4038 4039 /** 4040 * Synthesizes a localized pattern string that represents the current state of this 4041 * Format object. 4042 * 4043 * @see #applyPattern 4044 */ 4045 public String toLocalizedPattern() { 4046 if (style == NumberFormat.PLURALCURRENCYSTYLE) { 4047 return formatPattern; 4048 } 4049 return toPattern(true); 4050 } 4051 4052 /** 4053 * Expands the affix pattern strings into the expanded affix strings. If any affix 4054 * pattern string is null, do not expand it. This method should be called any time the 4055 * symbols or the affix patterns change in order to keep the expanded affix strings up 4056 * to date. This method also will be called before formatting if format currency 4057 * plural names, since the plural name is not a static one, it is based on the 4058 * currency plural count, the affix will be known only after the currency plural count 4059 * is know. In which case, the parameter 'pluralCount' will be a non-null currency 4060 * plural count. In all other cases, the 'pluralCount' is null, which means it is not 4061 * needed. 4062 */ 4063 // Bug 4212072 [Richard/GCL] 4064 private void expandAffixes(String pluralCount) { 4065 // expandAffix() will set currencyChoice to a non-null value if 4066 // appropriate AND if it is null. 4067 currencyChoice = null; 4068 4069 // Reuse one StringBuffer for better performance 4070 StringBuffer buffer = new StringBuffer(); 4071 if (posPrefixPattern != null) { 4072 expandAffix(posPrefixPattern, pluralCount, buffer); 4073 positivePrefix = buffer.toString(); 4074 } 4075 if (posSuffixPattern != null) { 4076 expandAffix(posSuffixPattern, pluralCount, buffer); 4077 positiveSuffix = buffer.toString(); 4078 } 4079 if (negPrefixPattern != null) { 4080 expandAffix(negPrefixPattern, pluralCount, buffer); 4081 negativePrefix = buffer.toString(); 4082 } 4083 if (negSuffixPattern != null) { 4084 expandAffix(negSuffixPattern, pluralCount, buffer); 4085 negativeSuffix = buffer.toString(); 4086 } 4087 } 4088 4089 /** 4090 * Expands an affix pattern into an affix string. All characters in the pattern are 4091 * literal unless bracketed by QUOTEs. The following characters outside QUOTE are 4092 * recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, PATTERN_MINUS, and 4093 * CURRENCY_SIGN. If CURRENCY_SIGN is doubled, it is interpreted as an international 4094 * currency sign. If CURRENCY_SIGN is tripled, it is interpreted as currency plural 4095 * long names, such as "US Dollars". Any other character outside QUOTE represents 4096 * itself. Quoted text must be well-formed. 4097 * 4098 * This method is used in two distinct ways. First, it is used to expand the stored 4099 * affix patterns into actual affixes. For this usage, doFormat must be false. Second, 4100 * it is used to expand the stored affix patterns given a specific number (doFormat == 4101 * true), for those rare cases in which a currency format references a ChoiceFormat 4102 * (e.g., en_IN display name for INR). The number itself is taken from digitList. 4103 * TODO: There are no currency ChoiceFormat patterns, figure out what is still relevant here. 4104 * 4105 * When used in the first way, this method has a side effect: It sets currencyChoice 4106 * to a ChoiceFormat object, if the currency's display name in this locale is a 4107 * ChoiceFormat pattern (very rare). It only does this if currencyChoice is null to 4108 * start with. 4109 * 4110 * @param pattern the non-null, possibly empty pattern 4111 * @param pluralCount the plural count. It is only used for currency plural format. In 4112 * which case, it is the plural count of the currency amount. For example, in en_US, 4113 * it is the singular "one", or the plural "other". For all other cases, it is null, 4114 * and is not being used. 4115 * @param buffer a scratch StringBuffer; its contents will be lost 4116 */ 4117 // Bug 4212072 [Richard/GCL] 4118 private void expandAffix(String pattern, String pluralCount, StringBuffer buffer) { 4119 buffer.setLength(0); 4120 for (int i = 0; i < pattern.length();) { 4121 char c = pattern.charAt(i++); 4122 if (c == QUOTE) { 4123 for (;;) { 4124 int j = pattern.indexOf(QUOTE, i); 4125 if (j == i) { 4126 buffer.append(QUOTE); 4127 i = j + 1; 4128 break; 4129 } else if (j > i) { 4130 buffer.append(pattern.substring(i, j)); 4131 i = j + 1; 4132 if (i < pattern.length() && pattern.charAt(i) == QUOTE) { 4133 buffer.append(QUOTE); 4134 ++i; 4135 // loop again 4136 } else { 4137 break; 4138 } 4139 } else { 4140 // Unterminated quote; should be caught by apply 4141 // pattern. 4142 throw new RuntimeException(); 4143 } 4144 } 4145 continue; 4146 } 4147 4148 switch (c) { 4149 case CURRENCY_SIGN: 4150 // As of ICU 2.2 we use the currency object, and ignore the currency 4151 // symbols in the DFS, unless we have a null currency object. This occurs 4152 // if resurrecting a pre-2.2 object or if the user sets a custom DFS. 4153 boolean intl = i < pattern.length() && pattern.charAt(i) == CURRENCY_SIGN; 4154 boolean plural = false; 4155 if (intl) { 4156 ++i; 4157 if (i < pattern.length() && pattern.charAt(i) == CURRENCY_SIGN) { 4158 plural = true; 4159 intl = false; 4160 ++i; 4161 } 4162 } 4163 String s = null; 4164 Currency currency = getCurrency(); 4165 if (currency != null) { 4166 // plural name is only needed when pluralCount != null, which means 4167 // when formatting currency plural names. For other cases, 4168 // pluralCount == null, and plural names are not needed. 4169 if (plural && pluralCount != null) { 4170 s = currency.getName(symbols.getULocale(), Currency.PLURAL_LONG_NAME, 4171 pluralCount, null); 4172 } else if (!intl) { 4173 s = currency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null); 4174 } else { 4175 s = currency.getCurrencyCode(); 4176 } 4177 } else { 4178 s = intl ? symbols.getInternationalCurrencySymbol() : 4179 symbols.getCurrencySymbol(); 4180 } 4181 // Here is where FieldPosition could be set for CURRENCY PLURAL. 4182 buffer.append(s); 4183 break; 4184 case PATTERN_PERCENT: 4185 buffer.append(symbols.getPercentString()); 4186 break; 4187 case PATTERN_PER_MILLE: 4188 buffer.append(symbols.getPerMillString()); 4189 break; 4190 case PATTERN_MINUS_SIGN: 4191 buffer.append(symbols.getMinusSignString()); 4192 break; 4193 default: 4194 buffer.append(c); 4195 break; 4196 } 4197 } 4198 } 4199 4200 /** 4201 * Append an affix to the given StringBuffer. 4202 * 4203 * @param buf 4204 * buffer to append to 4205 * @param isNegative 4206 * @param isPrefix 4207 * @param fieldPosition 4208 * @param parseAttr 4209 */ 4210 private int appendAffix(StringBuffer buf, boolean isNegative, boolean isPrefix, 4211 FieldPosition fieldPosition, 4212 boolean parseAttr) { 4213 if (currencyChoice != null) { 4214 String affixPat = null; 4215 if (isPrefix) { 4216 affixPat = isNegative ? negPrefixPattern : posPrefixPattern; 4217 } else { 4218 affixPat = isNegative ? negSuffixPattern : posSuffixPattern; 4219 } 4220 StringBuffer affixBuf = new StringBuffer(); 4221 expandAffix(affixPat, null, affixBuf); 4222 buf.append(affixBuf); 4223 return affixBuf.length(); 4224 } 4225 4226 String affix = null; 4227 String pattern; 4228 if (isPrefix) { 4229 affix = isNegative ? negativePrefix : positivePrefix; 4230 pattern = isNegative ? negPrefixPattern : posPrefixPattern; 4231 } else { 4232 affix = isNegative ? negativeSuffix : positiveSuffix; 4233 pattern = isNegative ? negSuffixPattern : posSuffixPattern; 4234 } 4235 // [Spark/CDL] Invoke formatAffix2Attribute to add attributes for affix 4236 if (parseAttr) { 4237 // Updates for Ticket 11805. 4238 int offset = affix.indexOf(symbols.getCurrencySymbol()); 4239 if (offset > -1) { 4240 formatAffix2Attribute(isPrefix, Field.CURRENCY, buf, offset, 4241 symbols.getCurrencySymbol().length()); 4242 } 4243 offset = affix.indexOf(symbols.getMinusSignString()); 4244 if (offset > -1) { 4245 formatAffix2Attribute(isPrefix, Field.SIGN, buf, offset, 4246 symbols.getMinusSignString().length()); 4247 } 4248 offset = affix.indexOf(symbols.getPercentString()); 4249 if (offset > -1) { 4250 formatAffix2Attribute(isPrefix, Field.PERCENT, buf, offset, 4251 symbols.getPercentString().length()); 4252 } 4253 offset = affix.indexOf(symbols.getPerMillString()); 4254 if (offset > -1) { 4255 formatAffix2Attribute(isPrefix, Field.PERMILLE, buf, offset, 4256 symbols.getPerMillString().length()); 4257 } 4258 offset = pattern.indexOf("¤¤¤"); 4259 if (offset > -1) { 4260 formatAffix2Attribute(isPrefix, Field.CURRENCY, buf, offset, 4261 affix.length() - offset); 4262 } 4263 } 4264 4265 // Look for SIGN, PERCENT, PERMILLE in the formatted affix. 4266 if (fieldPosition.getFieldAttribute() == NumberFormat.Field.SIGN) { 4267 String sign = isNegative ? symbols.getMinusSignString() : symbols.getPlusSignString(); 4268 int firstPos = affix.indexOf(sign); 4269 if (firstPos > -1) { 4270 int startPos = buf.length() + firstPos; 4271 fieldPosition.setBeginIndex(startPos); 4272 fieldPosition.setEndIndex(startPos + sign.length()); 4273 } 4274 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.PERCENT) { 4275 int firstPos = affix.indexOf(symbols.getPercentString()); 4276 if (firstPos > -1) { 4277 int startPos = buf.length() + firstPos; 4278 fieldPosition.setBeginIndex(startPos); 4279 fieldPosition.setEndIndex(startPos + symbols.getPercentString().length()); 4280 } 4281 } else if (fieldPosition.getFieldAttribute() == NumberFormat.Field.PERMILLE) { 4282 int firstPos = affix.indexOf(symbols.getPerMillString()); 4283 if (firstPos > -1) { 4284 int startPos = buf.length() + firstPos; 4285 fieldPosition.setBeginIndex(startPos); 4286 fieldPosition.setEndIndex(startPos + symbols.getPerMillString().length()); 4287 } 4288 } else 4289 // If CurrencySymbol or InternationalCurrencySymbol is in the affix, check for currency symbol. 4290 // Get spelled out name if "¤¤¤" is in the pattern. 4291 if (fieldPosition.getFieldAttribute() == NumberFormat.Field.CURRENCY) { 4292 if (affix.indexOf(symbols.getCurrencySymbol()) > -1) { 4293 String aff = symbols.getCurrencySymbol(); 4294 int firstPos = affix.indexOf(aff); 4295 int start = buf.length() + firstPos; 4296 int end = start + aff.length(); 4297 fieldPosition.setBeginIndex(start); 4298 fieldPosition.setEndIndex(end); 4299 } else if (affix.indexOf(symbols.getInternationalCurrencySymbol()) > -1) { 4300 String aff = symbols.getInternationalCurrencySymbol(); 4301 int firstPos = affix.indexOf(aff); 4302 int start = buf.length() + firstPos; 4303 int end = start + aff.length(); 4304 fieldPosition.setBeginIndex(start); 4305 fieldPosition.setEndIndex(end); 4306 } else if (pattern.indexOf("¤¤¤") > -1) { 4307 // It's a plural, and we know where it is in the pattern. 4308 int firstPos = pattern.indexOf("¤¤¤"); 4309 int start = buf.length() + firstPos; 4310 int end = buf.length() + affix.length(); // This seems clunky and wrong. 4311 fieldPosition.setBeginIndex(start); 4312 fieldPosition.setEndIndex(end); 4313 } 4314 } 4315 4316 buf.append(affix); 4317 return affix.length(); 4318 } 4319 4320 // Fix for prefix and suffix in Ticket 11805. 4321 private void formatAffix2Attribute(boolean isPrefix, Field fieldType, 4322 StringBuffer buf, int offset, int symbolSize) { 4323 int begin; 4324 begin = offset; 4325 if (!isPrefix) { 4326 begin += buf.length(); 4327 } 4328 4329 addAttribute(fieldType, begin, begin + symbolSize); 4330 } 4331 4332 /** 4333 * [Spark/CDL] Use this method to add attribute. 4334 */ 4335 private void addAttribute(Field field, int begin, int end) { 4336 FieldPosition pos = new FieldPosition(field); 4337 pos.setBeginIndex(begin); 4338 pos.setEndIndex(end); 4339 attributes.add(pos); 4340 } 4341 4342 /** 4343 * Formats the object to an attributed string, and return the corresponding iterator. 4344 */ 4345 @Override 4346 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 4347 return formatToCharacterIterator(obj, NULL_UNIT); 4348 } 4349 4350 AttributedCharacterIterator formatToCharacterIterator(Object obj, Unit unit) { 4351 if (!(obj instanceof Number)) 4352 throw new IllegalArgumentException(); 4353 Number number = (Number) obj; 4354 StringBuffer text = new StringBuffer(); 4355 unit.writePrefix(text); 4356 attributes.clear(); 4357 if (obj instanceof BigInteger) { 4358 format((BigInteger) number, text, new FieldPosition(0), true); 4359 } else if (obj instanceof java.math.BigDecimal) { 4360 format((java.math.BigDecimal) number, text, new FieldPosition(0) 4361 , true); 4362 } else if (obj instanceof Double) { 4363 format(number.doubleValue(), text, new FieldPosition(0), true); 4364 } else if (obj instanceof Integer || obj instanceof Long) { 4365 format(number.longValue(), text, new FieldPosition(0), true); 4366 } else { 4367 throw new IllegalArgumentException(); 4368 } 4369 unit.writeSuffix(text); 4370 AttributedString as = new AttributedString(text.toString()); 4371 4372 // add NumberFormat field attributes to the AttributedString 4373 for (int i = 0; i < attributes.size(); i++) { 4374 FieldPosition pos = attributes.get(i); 4375 Format.Field attribute = pos.getFieldAttribute(); 4376 as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos.getEndIndex()); 4377 } 4378 4379 // return the CharacterIterator from AttributedString 4380 return as.getIterator(); 4381 } 4382 4383 /** 4384 * Appends an affix pattern to the given StringBuffer. Localize unquoted specials. 4385 * <p> 4386 * <b>Note:</b> This implementation does not support new String localized symbols. 4387 */ 4388 private void appendAffixPattern(StringBuffer buffer, boolean isNegative, boolean isPrefix, 4389 boolean localized) { 4390 String affixPat = null; 4391 if (isPrefix) { 4392 affixPat = isNegative ? negPrefixPattern : posPrefixPattern; 4393 } else { 4394 affixPat = isNegative ? negSuffixPattern : posSuffixPattern; 4395 } 4396 4397 // When there is a null affix pattern, we use the affix itself. 4398 if (affixPat == null) { 4399 String affix = null; 4400 if (isPrefix) { 4401 affix = isNegative ? negativePrefix : positivePrefix; 4402 } else { 4403 affix = isNegative ? negativeSuffix : positiveSuffix; 4404 } 4405 // Do this crudely for now: Wrap everything in quotes. 4406 buffer.append(QUOTE); 4407 for (int i = 0; i < affix.length(); ++i) { 4408 char ch = affix.charAt(i); 4409 if (ch == QUOTE) { 4410 buffer.append(ch); 4411 } 4412 buffer.append(ch); 4413 } 4414 buffer.append(QUOTE); 4415 return; 4416 } 4417 4418 if (!localized) { 4419 buffer.append(affixPat); 4420 } else { 4421 int i, j; 4422 for (i = 0; i < affixPat.length(); ++i) { 4423 char ch = affixPat.charAt(i); 4424 switch (ch) { 4425 case QUOTE: 4426 j = affixPat.indexOf(QUOTE, i + 1); 4427 if (j < 0) { 4428 throw new IllegalArgumentException("Malformed affix pattern: " + affixPat); 4429 } 4430 buffer.append(affixPat.substring(i, j + 1)); 4431 i = j; 4432 continue; 4433 case PATTERN_PER_MILLE: 4434 ch = symbols.getPerMill(); 4435 break; 4436 case PATTERN_PERCENT: 4437 ch = symbols.getPercent(); 4438 break; 4439 case PATTERN_MINUS_SIGN: 4440 ch = symbols.getMinusSign(); 4441 break; 4442 } 4443 // check if char is same as any other symbol 4444 if (ch == symbols.getDecimalSeparator() || ch == symbols.getGroupingSeparator()) { 4445 buffer.append(QUOTE); 4446 buffer.append(ch); 4447 buffer.append(QUOTE); 4448 } else { 4449 buffer.append(ch); 4450 } 4451 } 4452 } 4453 } 4454 4455 /** 4456 * Does the real work of generating a pattern. 4457 * <p> 4458 * <b>Note:</b> This implementation does not support new String localized symbols. 4459 */ 4460 private String toPattern(boolean localized) { 4461 StringBuffer result = new StringBuffer(); 4462 char zero = localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT; 4463 char digit = localized ? symbols.getDigit() : PATTERN_DIGIT; 4464 char sigDigit = 0; 4465 boolean useSigDig = areSignificantDigitsUsed(); 4466 if (useSigDig) { 4467 sigDigit = localized ? symbols.getSignificantDigit() : PATTERN_SIGNIFICANT_DIGIT; 4468 } 4469 char group = localized ? symbols.getGroupingSeparator() : PATTERN_GROUPING_SEPARATOR; 4470 int i; 4471 int roundingDecimalPos = 0; // Pos of decimal in roundingDigits 4472 String roundingDigits = null; 4473 int padPos = (formatWidth > 0) ? padPosition : -1; 4474 String padSpec = (formatWidth > 0) 4475 ? new StringBuffer(2).append(localized 4476 ? symbols.getPadEscape() 4477 : PATTERN_PAD_ESCAPE).append(pad).toString() 4478 : null; 4479 if (roundingIncrementICU != null) { 4480 i = roundingIncrementICU.scale(); 4481 roundingDigits = roundingIncrementICU.movePointRight(i).toString(); 4482 roundingDecimalPos = roundingDigits.length() - i; 4483 } 4484 for (int part = 0; part < 2; ++part) { 4485 // variable not used int partStart = result.length(); 4486 if (padPos == PAD_BEFORE_PREFIX) { 4487 result.append(padSpec); 4488 } 4489 4490 // Use original symbols read from resources in pattern eg. use "\u00A4" 4491 // instead of "$" in Locale.US [Richard/GCL] 4492 appendAffixPattern(result, part != 0, true, localized); 4493 if (padPos == PAD_AFTER_PREFIX) { 4494 result.append(padSpec); 4495 } 4496 int sub0Start = result.length(); 4497 int g = isGroupingUsed() ? Math.max(0, groupingSize) : 0; 4498 if (g > 0 && groupingSize2 > 0 && groupingSize2 != groupingSize) { 4499 g += groupingSize2; 4500 } 4501 int maxDig = 0, minDig = 0, maxSigDig = 0; 4502 if (useSigDig) { 4503 minDig = getMinimumSignificantDigits(); 4504 maxDig = maxSigDig = getMaximumSignificantDigits(); 4505 } else { 4506 minDig = getMinimumIntegerDigits(); 4507 maxDig = getMaximumIntegerDigits(); 4508 } 4509 if (useExponentialNotation) { 4510 if (maxDig > MAX_SCIENTIFIC_INTEGER_DIGITS) { 4511 maxDig = 1; 4512 } 4513 } else if (useSigDig) { 4514 maxDig = Math.max(maxDig, g + 1); 4515 } else { 4516 maxDig = Math.max(Math.max(g, getMinimumIntegerDigits()), roundingDecimalPos) + 1; 4517 } 4518 for (i = maxDig; i > 0; --i) { 4519 if (!useExponentialNotation && i < maxDig && isGroupingPosition(i)) { 4520 result.append(group); 4521 } 4522 if (useSigDig) { 4523 // #@,@### (maxSigDig == 5, minSigDig == 2) 65 4321 (1-based pos, 4524 // count from the right) Use # if pos > maxSigDig or 1 <= pos <= 4525 // (maxSigDig - minSigDig) Use @ if (maxSigDig - minSigDig) < pos <= 4526 // maxSigDig 4527 result.append((maxSigDig >= i && i > (maxSigDig - minDig)) ? sigDigit : digit); 4528 } else { 4529 if (roundingDigits != null) { 4530 int pos = roundingDecimalPos - i; 4531 if (pos >= 0 && pos < roundingDigits.length()) { 4532 result.append((char) (roundingDigits.charAt(pos) - '0' + zero)); 4533 continue; 4534 } 4535 } 4536 result.append(i <= minDig ? zero : digit); 4537 } 4538 } 4539 if (!useSigDig) { 4540 if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) { 4541 result.append(localized ? symbols.getDecimalSeparator() : 4542 PATTERN_DECIMAL_SEPARATOR); 4543 } 4544 int pos = roundingDecimalPos; 4545 for (i = 0; i < getMaximumFractionDigits(); ++i) { 4546 if (roundingDigits != null && pos < roundingDigits.length()) { 4547 result.append(pos < 0 ? zero : 4548 (char) (roundingDigits.charAt(pos) - '0' + zero)); 4549 ++pos; 4550 continue; 4551 } 4552 result.append(i < getMinimumFractionDigits() ? zero : digit); 4553 } 4554 } 4555 if (useExponentialNotation) { 4556 if (localized) { 4557 result.append(symbols.getExponentSeparator()); 4558 } else { 4559 result.append(PATTERN_EXPONENT); 4560 } 4561 if (exponentSignAlwaysShown) { 4562 result.append(localized ? symbols.getPlusSign() : PATTERN_PLUS_SIGN); 4563 } 4564 for (i = 0; i < minExponentDigits; ++i) { 4565 result.append(zero); 4566 } 4567 } 4568 if (padSpec != null && !useExponentialNotation) { 4569 int add = formatWidth 4570 - result.length() 4571 + sub0Start 4572 - ((part == 0) 4573 ? positivePrefix.length() + positiveSuffix.length() 4574 : negativePrefix.length() + negativeSuffix.length()); 4575 while (add > 0) { 4576 result.insert(sub0Start, digit); 4577 ++maxDig; 4578 --add; 4579 // Only add a grouping separator if we have at least 2 additional 4580 // characters to be added, so we don't end up with ",###". 4581 if (add > 1 && isGroupingPosition(maxDig)) { 4582 result.insert(sub0Start, group); 4583 --add; 4584 } 4585 } 4586 } 4587 if (padPos == PAD_BEFORE_SUFFIX) { 4588 result.append(padSpec); 4589 } 4590 // Use original symbols read from resources in pattern eg. use "\u00A4" 4591 // instead of "$" in Locale.US [Richard/GCL] 4592 appendAffixPattern(result, part != 0, false, localized); 4593 if (padPos == PAD_AFTER_SUFFIX) { 4594 result.append(padSpec); 4595 } 4596 if (part == 0) { 4597 if (negativeSuffix.equals(positiveSuffix) && 4598 negativePrefix.equals(PATTERN_MINUS_SIGN + positivePrefix)) { 4599 break; 4600 } else { 4601 result.append(localized ? symbols.getPatternSeparator() : PATTERN_SEPARATOR); 4602 } 4603 } 4604 } 4605 return result.toString(); 4606 } 4607 4608 /** 4609 * Applies the given pattern to this Format object. A pattern is a short-hand 4610 * specification for the various formatting properties. These properties can also be 4611 * changed individually through the various setter methods. 4612 * 4613 * <p>There is no limit to integer digits are set by this routine, since that is the 4614 * typical end-user desire; use setMaximumInteger if you want to set a real value. For 4615 * negative numbers, use a second pattern, separated by a semicolon 4616 * 4617 * <p>Example "#,#00.0#" -> 1,234.56 4618 * 4619 * <p>This means a minimum of 2 integer digits, 1 fraction digit, and a maximum of 2 4620 * fraction digits. 4621 * 4622 * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parentheses. 4623 * 4624 * <p>In negative patterns, the minimum and maximum counts are ignored; these are 4625 * presumed to be set in the positive pattern. 4626 */ 4627 public void applyPattern(String pattern) { 4628 applyPattern(pattern, false); 4629 } 4630 4631 /** 4632 * Applies the given pattern to this Format object. The pattern is assumed to be in a 4633 * localized notation. A pattern is a short-hand specification for the various 4634 * formatting properties. These properties can also be changed individually through 4635 * the various setter methods. 4636 * 4637 * <p>There is no limit to integer digits are set by this routine, since that is the 4638 * typical end-user desire; use setMaximumInteger if you want to set a real value. For 4639 * negative numbers, use a second pattern, separated by a semicolon 4640 * 4641 * <p>Example "#,#00.0#" -> 1,234.56 4642 * 4643 * <p>This means a minimum of 2 integer digits, 1 fraction digit, and a maximum of 2 4644 * fraction digits. 4645 * 4646 * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses. 4647 * 4648 * <p>In negative patterns, the minimum and maximum counts are ignored; these are 4649 * presumed to be set in the positive pattern. 4650 */ 4651 public void applyLocalizedPattern(String pattern) { 4652 applyPattern(pattern, true); 4653 } 4654 4655 /** 4656 * Does the real work of applying a pattern. 4657 */ 4658 private void applyPattern(String pattern, boolean localized) { 4659 applyPatternWithoutExpandAffix(pattern, localized); 4660 expandAffixAdjustWidth(null); 4661 } 4662 4663 private void expandAffixAdjustWidth(String pluralCount) { 4664 // Bug 4212072 Update the affix strings according to symbols in order to keep the 4665 // affix strings up to date. [Richard/GCL] 4666 expandAffixes(pluralCount); 4667 4668 // Now that we have the actual prefix and suffix, fix up formatWidth 4669 if (formatWidth > 0) { 4670 formatWidth += positivePrefix.length() + positiveSuffix.length(); 4671 } 4672 } 4673 4674 private void applyPatternWithoutExpandAffix(String pattern, boolean localized) { 4675 char zeroDigit = PATTERN_ZERO_DIGIT; // '0' 4676 char sigDigit = PATTERN_SIGNIFICANT_DIGIT; // '@' 4677 char groupingSeparator = PATTERN_GROUPING_SEPARATOR; 4678 char decimalSeparator = PATTERN_DECIMAL_SEPARATOR; 4679 char percent = PATTERN_PERCENT; 4680 char perMill = PATTERN_PER_MILLE; 4681 char digit = PATTERN_DIGIT; // '#' 4682 char separator = PATTERN_SEPARATOR; 4683 String exponent = String.valueOf(PATTERN_EXPONENT); 4684 char plus = PATTERN_PLUS_SIGN; 4685 char padEscape = PATTERN_PAD_ESCAPE; 4686 char minus = PATTERN_MINUS_SIGN; // Bug 4212072 [Richard/GCL] 4687 if (localized) { 4688 zeroDigit = symbols.getZeroDigit(); 4689 sigDigit = symbols.getSignificantDigit(); 4690 groupingSeparator = symbols.getGroupingSeparator(); 4691 decimalSeparator = symbols.getDecimalSeparator(); 4692 percent = symbols.getPercent(); 4693 perMill = symbols.getPerMill(); 4694 digit = symbols.getDigit(); 4695 separator = symbols.getPatternSeparator(); 4696 exponent = symbols.getExponentSeparator(); 4697 plus = symbols.getPlusSign(); 4698 padEscape = symbols.getPadEscape(); 4699 minus = symbols.getMinusSign(); // Bug 4212072 [Richard/GCL] 4700 } 4701 char nineDigit = (char) (zeroDigit + 9); 4702 4703 boolean gotNegative = false; 4704 4705 int pos = 0; 4706 // Part 0 is the positive pattern. Part 1, if present, is the negative 4707 // pattern. 4708 for (int part = 0; part < 2 && pos < pattern.length(); ++part) { 4709 // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix, 2=suffix, 4710 // 3=prefix in quote, 4=suffix in quote. Subpart 0 is between the prefix and 4711 // suffix, and consists of pattern characters. In the prefix and suffix, 4712 // percent, permille, and currency symbols are recognized and translated. 4713 int subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0; 4714 4715 // It's important that we don't change any fields of this object 4716 // prematurely. We set the following variables for the multiplier, grouping, 4717 // etc., and then only change the actual object fields if everything parses 4718 // correctly. This also lets us register the data from part 0 and ignore the 4719 // part 1, except for the prefix and suffix. 4720 StringBuilder prefix = new StringBuilder(); 4721 StringBuilder suffix = new StringBuilder(); 4722 int decimalPos = -1; 4723 int multpl = 1; 4724 int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0; 4725 byte groupingCount = -1; 4726 byte groupingCount2 = -1; 4727 int padPos = -1; 4728 char padChar = 0; 4729 int incrementPos = -1; 4730 long incrementVal = 0; 4731 byte expDigits = -1; 4732 boolean expSignAlways = false; 4733 int currencySignCnt = 0; 4734 4735 // The affix is either the prefix or the suffix. 4736 StringBuilder affix = prefix; 4737 4738 int start = pos; 4739 4740 PARTLOOP: for (; pos < pattern.length(); ++pos) { 4741 char ch = pattern.charAt(pos); 4742 switch (subpart) { 4743 case 0: // Pattern proper subpart (between prefix & suffix) 4744 // Process the digits, decimal, and grouping characters. We record 4745 // five pieces of information. We expect the digits to occur in the 4746 // pattern ####00.00####, and we record the number of left digits, 4747 // zero (central) digits, and right digits. The position of the last 4748 // grouping character is recorded (should be somewhere within the 4749 // first two blocks of characters), as is the position of the decimal 4750 // point, if any (should be in the zero digits). If there is no 4751 // decimal point, then there should be no right digits. 4752 if (ch == digit) { 4753 if (zeroDigitCount > 0 || sigDigitCount > 0) { 4754 ++digitRightCount; 4755 } else { 4756 ++digitLeftCount; 4757 } 4758 if (groupingCount >= 0 && decimalPos < 0) { 4759 ++groupingCount; 4760 } 4761 } else if ((ch >= zeroDigit && ch <= nineDigit) || ch == sigDigit) { 4762 if (digitRightCount > 0) { 4763 patternError("Unexpected '" + ch + '\'', pattern); 4764 } 4765 if (ch == sigDigit) { 4766 ++sigDigitCount; 4767 } else { 4768 ++zeroDigitCount; 4769 if (ch != zeroDigit) { 4770 int p = digitLeftCount + zeroDigitCount + digitRightCount; 4771 if (incrementPos >= 0) { 4772 while (incrementPos < p) { 4773 incrementVal *= 10; 4774 ++incrementPos; 4775 } 4776 } else { 4777 incrementPos = p; 4778 } 4779 incrementVal += ch - zeroDigit; 4780 } 4781 } 4782 if (groupingCount >= 0 && decimalPos < 0) { 4783 ++groupingCount; 4784 } 4785 } else if (ch == groupingSeparator) { 4786 // Bug 4212072 process the Localized pattern like 4787 // "'Fr. '#'##0.05;'Fr.-'#'##0.05" (Locale="CH", groupingSeparator 4788 // == QUOTE) [Richard/GCL] 4789 if (ch == QUOTE && (pos + 1) < pattern.length()) { 4790 char after = pattern.charAt(pos + 1); 4791 if (!(after == digit || (after >= zeroDigit && after <= nineDigit))) { 4792 // A quote outside quotes indicates either the opening 4793 // quote or two quotes, which is a quote literal. That is, 4794 // we have the first quote in 'do' or o''clock. 4795 if (after == QUOTE) { 4796 ++pos; 4797 // Fall through to append(ch) 4798 } else { 4799 if (groupingCount < 0) { 4800 subpart = 3; // quoted prefix subpart 4801 } else { 4802 // Transition to suffix subpart 4803 subpart = 2; // suffix subpart 4804 affix = suffix; 4805 sub0Limit = pos--; 4806 } 4807 continue; 4808 } 4809 } 4810 } 4811 4812 if (decimalPos >= 0) { 4813 patternError("Grouping separator after decimal", pattern); 4814 } 4815 groupingCount2 = groupingCount; 4816 groupingCount = 0; 4817 } else if (ch == decimalSeparator) { 4818 if (decimalPos >= 0) { 4819 patternError("Multiple decimal separators", pattern); 4820 } 4821 // Intentionally incorporate the digitRightCount, even though it 4822 // is illegal for this to be > 0 at this point. We check pattern 4823 // syntax below. 4824 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; 4825 } else { 4826 if (pattern.regionMatches(pos, exponent, 0, exponent.length())) { 4827 if (expDigits >= 0) { 4828 patternError("Multiple exponential symbols", pattern); 4829 } 4830 if (groupingCount >= 0) { 4831 patternError("Grouping separator in exponential", pattern); 4832 } 4833 pos += exponent.length(); 4834 // Check for positive prefix 4835 if (pos < pattern.length() && pattern.charAt(pos) == plus) { 4836 expSignAlways = true; 4837 ++pos; 4838 } 4839 // Use lookahead to parse out the exponential part of the 4840 // pattern, then jump into suffix subpart. 4841 expDigits = 0; 4842 while (pos < pattern.length() && pattern.charAt(pos) == zeroDigit) { 4843 ++expDigits; 4844 ++pos; 4845 } 4846 4847 // 1. Require at least one mantissa pattern digit 4848 // 2. Disallow "#+ @" in mantissa 4849 // 3. Require at least one exponent pattern digit 4850 if (((digitLeftCount + zeroDigitCount) < 1 && 4851 (sigDigitCount + digitRightCount) < 1) 4852 || (sigDigitCount > 0 && digitLeftCount > 0) || expDigits < 1) { 4853 patternError("Malformed exponential", pattern); 4854 } 4855 } 4856 // Transition to suffix subpart 4857 subpart = 2; // suffix subpart 4858 affix = suffix; 4859 sub0Limit = pos--; // backup: for() will increment 4860 continue; 4861 } 4862 break; 4863 case 1: // Prefix subpart 4864 case 2: // Suffix subpart 4865 // Process the prefix / suffix characters Process unquoted characters 4866 // seen in prefix or suffix subpart. 4867 4868 // Several syntax characters implicitly begins the next subpart if we 4869 // are in the prefix; otherwise they are illegal if unquoted. 4870 if (ch == digit || ch == groupingSeparator || ch == decimalSeparator 4871 || (ch >= zeroDigit && ch <= nineDigit) || ch == sigDigit) { 4872 // Any of these characters implicitly begins the 4873 // next subpart if we are in the prefix 4874 if (subpart == 1) { // prefix subpart 4875 subpart = 0; // pattern proper subpart 4876 sub0Start = pos--; // Reprocess this character 4877 continue; 4878 } else if (ch == QUOTE) { 4879 // Bug 4212072 process the Localized pattern like 4880 // "'Fr. '#'##0.05;'Fr.-'#'##0.05" (Locale="CH", 4881 // groupingSeparator == QUOTE) [Richard/GCL] 4882 4883 // A quote outside quotes indicates either the opening quote 4884 // or two quotes, which is a quote literal. That is, we have 4885 // the first quote in 'do' or o''clock. 4886 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) { 4887 ++pos; 4888 affix.append(ch); 4889 } else { 4890 subpart += 2; // open quote 4891 } 4892 continue; 4893 } 4894 patternError("Unquoted special character '" + ch + '\'', pattern); 4895 } else if (ch == CURRENCY_SIGN) { 4896 // Use lookahead to determine if the currency sign is 4897 // doubled or not. 4898 boolean doubled = (pos + 1) < pattern.length() && 4899 pattern.charAt(pos + 1) == CURRENCY_SIGN; 4900 4901 // Bug 4212072 To meet the need of expandAffix(String, 4902 // StirngBuffer) [Richard/GCL] 4903 if (doubled) { 4904 ++pos; // Skip over the doubled character 4905 affix.append(ch); // append two: one here, one below 4906 if ((pos + 1) < pattern.length() && 4907 pattern.charAt(pos + 1) == CURRENCY_SIGN) { 4908 ++pos; // Skip over the tripled character 4909 affix.append(ch); // append again 4910 currencySignCnt = CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT; 4911 } else { 4912 currencySignCnt = CURRENCY_SIGN_COUNT_IN_ISO_FORMAT; 4913 } 4914 } else { 4915 currencySignCnt = CURRENCY_SIGN_COUNT_IN_SYMBOL_FORMAT; 4916 } 4917 // Fall through to append(ch) 4918 } else if (ch == QUOTE) { 4919 // A quote outside quotes indicates either the opening quote or 4920 // two quotes, which is a quote literal. That is, we have the 4921 // first quote in 'do' or o''clock. 4922 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) { 4923 ++pos; 4924 affix.append(ch); // append two: one here, one below 4925 } else { 4926 subpart += 2; // open quote 4927 } 4928 // Fall through to append(ch) 4929 } else if (ch == separator) { 4930 // Don't allow separators in the prefix, and don't allow 4931 // separators in the second pattern (part == 1). 4932 if (subpart == 1 || part == 1) { 4933 patternError("Unquoted special character '" + ch + '\'', pattern); 4934 } 4935 sub2Limit = pos++; 4936 break PARTLOOP; // Go to next part 4937 } else if (ch == percent || ch == perMill) { 4938 // Next handle characters which are appended directly. 4939 if (multpl != 1) { 4940 patternError("Too many percent/permille characters", pattern); 4941 } 4942 multpl = (ch == percent) ? 100 : 1000; 4943 // Convert to non-localized pattern 4944 ch = (ch == percent) ? PATTERN_PERCENT : PATTERN_PER_MILLE; 4945 // Fall through to append(ch) 4946 } else if (ch == minus) { 4947 // Convert to non-localized pattern 4948 ch = PATTERN_MINUS_SIGN; 4949 // Fall through to append(ch) 4950 } else if (ch == padEscape) { 4951 if (padPos >= 0) { 4952 patternError("Multiple pad specifiers", pattern); 4953 } 4954 if ((pos + 1) == pattern.length()) { 4955 patternError("Invalid pad specifier", pattern); 4956 } 4957 padPos = pos++; // Advance past pad char 4958 padChar = pattern.charAt(pos); 4959 continue; 4960 } 4961 affix.append(ch); 4962 break; 4963 case 3: // Prefix subpart, in quote 4964 case 4: // Suffix subpart, in quote 4965 // A quote within quotes indicates either the closing quote or two 4966 // quotes, which is a quote literal. That is, we have the second quote 4967 // in 'do' or 'don''t'. 4968 if (ch == QUOTE) { 4969 if ((pos + 1) < pattern.length() && pattern.charAt(pos + 1) == QUOTE) { 4970 ++pos; 4971 affix.append(ch); 4972 } else { 4973 subpart -= 2; // close quote 4974 } 4975 // Fall through to append(ch) 4976 } 4977 // NOTE: In ICU 2.2 there was code here to parse quoted percent and 4978 // permille characters _within quotes_ and give them special 4979 // meaning. This is incorrect, since quoted characters are literals 4980 // without special meaning. 4981 affix.append(ch); 4982 break; 4983 } 4984 } 4985 4986 if (subpart == 3 || subpart == 4) { 4987 patternError("Unterminated quote", pattern); 4988 } 4989 4990 if (sub0Limit == 0) { 4991 sub0Limit = pattern.length(); 4992 } 4993 4994 if (sub2Limit == 0) { 4995 sub2Limit = pattern.length(); 4996 } 4997 4998 // Handle patterns with no '0' pattern character. These patterns are legal, 4999 // but must be recodified to make sense. "##.###" -> "#0.###". ".###" -> 5000 // ".0##". 5001 // 5002 // We allow patterns of the form "####" to produce a zeroDigitCount of zero 5003 // (got that?); although this seems like it might make it possible for 5004 // format() to produce empty strings, format() checks for this condition and 5005 // outputs a zero digit in this situation. Having a zeroDigitCount of zero 5006 // yields a minimum integer digits of zero, which allows proper round-trip 5007 // patterns. We don't want "#" to become "#0" when toPattern() is called (even 5008 // though that's what it really is, semantically). 5009 if (zeroDigitCount == 0 && sigDigitCount == 0 && 5010 digitLeftCount > 0 && decimalPos >= 0) { 5011 // Handle "###.###" and "###." and ".###" 5012 int n = decimalPos; 5013 if (n == 0) 5014 ++n; // Handle ".###" 5015 digitRightCount = digitLeftCount - n; 5016 digitLeftCount = n - 1; 5017 zeroDigitCount = 1; 5018 } 5019 5020 // Do syntax checking on the digits, decimal points, and quotes. 5021 if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) 5022 || (decimalPos >= 0 5023 && (sigDigitCount > 0 5024 || decimalPos < digitLeftCount 5025 || decimalPos > (digitLeftCount + zeroDigitCount))) 5026 || groupingCount == 0 5027 || groupingCount2 == 0 5028 || (sigDigitCount > 0 && zeroDigitCount > 0) 5029 || subpart > 2) { // subpart > 2 == unmatched quote 5030 patternError("Malformed pattern", pattern); 5031 } 5032 5033 // Make sure pad is at legal position before or after affix. 5034 if (padPos >= 0) { 5035 if (padPos == start) { 5036 padPos = PAD_BEFORE_PREFIX; 5037 } else if (padPos + 2 == sub0Start) { 5038 padPos = PAD_AFTER_PREFIX; 5039 } else if (padPos == sub0Limit) { 5040 padPos = PAD_BEFORE_SUFFIX; 5041 } else if (padPos + 2 == sub2Limit) { 5042 padPos = PAD_AFTER_SUFFIX; 5043 } else { 5044 patternError("Illegal pad position", pattern); 5045 } 5046 } 5047 5048 if (part == 0) { 5049 // Set negative affixes temporarily to match the positive 5050 // affixes. Fix this up later after processing both parts. 5051 5052 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer) 5053 // [Richard/GCL] 5054 posPrefixPattern = negPrefixPattern = prefix.toString(); 5055 posSuffixPattern = negSuffixPattern = suffix.toString(); 5056 5057 useExponentialNotation = (expDigits >= 0); 5058 if (useExponentialNotation) { 5059 minExponentDigits = expDigits; 5060 exponentSignAlwaysShown = expSignAlways; 5061 } 5062 int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; 5063 // The effectiveDecimalPos is the position the decimal is at or would be 5064 // at if there is no decimal. Note that if decimalPos<0, then 5065 // digitTotalCount == digitLeftCount + zeroDigitCount. 5066 int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount; 5067 boolean useSigDig = (sigDigitCount > 0); 5068 setSignificantDigitsUsed(useSigDig); 5069 if (useSigDig) { 5070 setMinimumSignificantDigits(sigDigitCount); 5071 setMaximumSignificantDigits(sigDigitCount + digitRightCount); 5072 } else { 5073 int minInt = effectiveDecimalPos - digitLeftCount; 5074 setMinimumIntegerDigits(minInt); 5075 5076 // Upper limit on integer and fraction digits for a Java double 5077 // [Richard/GCL] 5078 setMaximumIntegerDigits(useExponentialNotation ? digitLeftCount + minInt : 5079 DOUBLE_INTEGER_DIGITS); 5080 _setMaximumFractionDigits(decimalPos >= 0 ? 5081 (digitTotalCount - decimalPos) : 0); 5082 setMinimumFractionDigits(decimalPos >= 0 ? 5083 (digitLeftCount + zeroDigitCount - decimalPos) : 0); 5084 } 5085 setGroupingUsed(groupingCount > 0); 5086 this.groupingSize = (groupingCount > 0) ? groupingCount : 0; 5087 this.groupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount) 5088 ? groupingCount2 : 0; 5089 this.multiplier = multpl; 5090 setDecimalSeparatorAlwaysShown(decimalPos == 0 || decimalPos == digitTotalCount); 5091 if (padPos >= 0) { 5092 padPosition = padPos; 5093 formatWidth = sub0Limit - sub0Start; // to be fixed up below 5094 pad = padChar; 5095 } else { 5096 formatWidth = 0; 5097 } 5098 if (incrementVal != 0) { 5099 // BigDecimal scale cannot be negative (even though this makes perfect 5100 // sense), so we need to handle this. 5101 int scale = incrementPos - effectiveDecimalPos; 5102 roundingIncrementICU = BigDecimal.valueOf(incrementVal, scale > 0 ? scale : 0); 5103 if (scale < 0) { 5104 roundingIncrementICU = roundingIncrementICU.movePointRight(-scale); 5105 } 5106 roundingMode = BigDecimal.ROUND_HALF_EVEN; 5107 } else { 5108 setRoundingIncrement((BigDecimal) null); 5109 } 5110 5111 // Update currency sign count for the new pattern 5112 currencySignCount = currencySignCnt; 5113 } else { 5114 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer) 5115 // [Richard/GCL] 5116 negPrefixPattern = prefix.toString(); 5117 negSuffixPattern = suffix.toString(); 5118 gotNegative = true; 5119 } 5120 } 5121 5122 5123 // Bug 4140009 Process the empty pattern [Richard/GCL] 5124 if (pattern.length() == 0) { 5125 posPrefixPattern = posSuffixPattern = ""; 5126 setMinimumIntegerDigits(0); 5127 setMaximumIntegerDigits(DOUBLE_INTEGER_DIGITS); 5128 setMinimumFractionDigits(0); 5129 _setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS); 5130 } 5131 5132 // If there was no negative pattern, or if the negative pattern is identical to 5133 // the positive pattern, then prepend the minus sign to the positive pattern to 5134 // form the negative pattern. 5135 5136 // Bug 4212072 To meet the need of expandAffix(String, StirngBuffer) [Richard/GCL] 5137 5138 if (!gotNegative || 5139 (negPrefixPattern.equals(posPrefixPattern) 5140 && negSuffixPattern.equals(posSuffixPattern))) { 5141 negSuffixPattern = posSuffixPattern; 5142 negPrefixPattern = PATTERN_MINUS_SIGN + posPrefixPattern; 5143 } 5144 setLocale(null, null); 5145 // save the pattern 5146 formatPattern = pattern; 5147 5148 // special handlings for currency instance 5149 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) { 5150 // reset rounding increment and max/min fractional digits 5151 // by the currency 5152 Currency theCurrency = getCurrency(); 5153 if (theCurrency != null) { 5154 setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage)); 5155 int d = theCurrency.getDefaultFractionDigits(currencyUsage); 5156 setMinimumFractionDigits(d); 5157 _setMaximumFractionDigits(d); 5158 } 5159 5160 // initialize currencyPluralInfo if needed 5161 if (currencySignCount == CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT 5162 && currencyPluralInfo == null) { 5163 currencyPluralInfo = new CurrencyPluralInfo(symbols.getULocale()); 5164 } 5165 } 5166 resetActualRounding(); 5167 } 5168 5169 5170 private void patternError(String msg, String pattern) { 5171 throw new IllegalArgumentException(msg + " in pattern \"" + pattern + '"'); 5172 } 5173 5174 5175 // Rewrite the following 4 "set" methods Upper limit on integer and fraction digits 5176 // for a Java double [Richard/GCL] 5177 5178 /** 5179 * Sets the maximum number of digits allowed in the integer portion of a number. This 5180 * override limits the integer digit count to 2,000,000,000 to match ICU4C. 5181 * 5182 * @see NumberFormat#setMaximumIntegerDigits 5183 */ 5184 @Override 5185 public void setMaximumIntegerDigits(int newValue) { 5186 // Android changed: Allow 2 billion integer digits. 5187 super.setMaximumIntegerDigits(Math.min(newValue, MAX_INTEGER_DIGITS)); 5188 } 5189 5190 /** 5191 * Sets the minimum number of digits allowed in the integer portion of a number. This 5192 * override limits the integer digit count to 309. 5193 * 5194 * @see NumberFormat#setMinimumIntegerDigits 5195 */ 5196 @Override 5197 public void setMinimumIntegerDigits(int newValue) { 5198 super.setMinimumIntegerDigits(Math.min(newValue, DOUBLE_INTEGER_DIGITS)); 5199 } 5200 5201 /** 5202 * <strong>[icu]</strong> Returns the minimum number of significant digits that will be 5203 * displayed. This value has no effect unless {@link #areSignificantDigitsUsed()} 5204 * returns true. 5205 * 5206 * @return the fewest significant digits that will be shown 5207 */ 5208 public int getMinimumSignificantDigits() { 5209 return minSignificantDigits; 5210 } 5211 5212 /** 5213 * <strong>[icu]</strong> Returns the maximum number of significant digits that will be 5214 * displayed. This value has no effect unless {@link #areSignificantDigitsUsed()} 5215 * returns true. 5216 * 5217 * @return the most significant digits that will be shown 5218 */ 5219 public int getMaximumSignificantDigits() { 5220 return maxSignificantDigits; 5221 } 5222 5223 /** 5224 * <strong>[icu]</strong> Sets the minimum number of significant digits that will be displayed. If 5225 * <code>min</code> is less than one then it is set to one. If the maximum significant 5226 * digits count is less than <code>min</code>, then it is set to <code>min</code>. 5227 * This function also enables the use of significant digits by this formatter - 5228 * {@link #areSignificantDigitsUsed()} will return true. 5229 * 5230 * @param min the fewest significant digits to be shown 5231 */ 5232 public void setMinimumSignificantDigits(int min) { 5233 if (min < 1) { 5234 min = 1; 5235 } 5236 // pin max sig dig to >= min 5237 int max = Math.max(maxSignificantDigits, min); 5238 minSignificantDigits = min; 5239 maxSignificantDigits = max; 5240 setSignificantDigitsUsed(true); 5241 } 5242 5243 /** 5244 * <strong>[icu]</strong> Sets the maximum number of significant digits that will be displayed. If 5245 * <code>max</code> is less than one then it is set to one. If the minimum significant 5246 * digits count is greater than <code>max</code>, then it is set to <code>max</code>. 5247 * This function also enables the use of significant digits by this formatter - 5248 * {@link #areSignificantDigitsUsed()} will return true. 5249 * 5250 * @param max the most significant digits to be shown 5251 */ 5252 public void setMaximumSignificantDigits(int max) { 5253 if (max < 1) { 5254 max = 1; 5255 } 5256 // pin min sig dig to 1..max 5257 int min = Math.min(minSignificantDigits, max); 5258 minSignificantDigits = min; 5259 maxSignificantDigits = max; 5260 setSignificantDigitsUsed(true); 5261 } 5262 5263 /** 5264 * <strong>[icu]</strong> Returns true if significant digits are in use or false if integer and 5265 * fraction digit counts are in use. 5266 * 5267 * @return true if significant digits are in use 5268 */ 5269 public boolean areSignificantDigitsUsed() { 5270 return useSignificantDigits; 5271 } 5272 5273 /** 5274 * <strong>[icu]</strong> Sets whether significant digits are in use, or integer and fraction digit 5275 * counts are in use. 5276 * 5277 * @param useSignificantDigits true to use significant digits, or false to use integer 5278 * and fraction digit counts 5279 */ 5280 public void setSignificantDigitsUsed(boolean useSignificantDigits) { 5281 this.useSignificantDigits = useSignificantDigits; 5282 } 5283 5284 /** 5285 * Sets the <tt>Currency</tt> object used to display currency amounts. This takes 5286 * effect immediately, if this format is a currency format. If this format is not a 5287 * currency format, then the currency object is used if and when this object becomes a 5288 * currency format through the application of a new pattern. 5289 * 5290 * @param theCurrency new currency object to use. Must not be null. 5291 */ 5292 @Override 5293 public void setCurrency(Currency theCurrency) { 5294 // If we are a currency format, then modify our affixes to 5295 // encode the currency symbol for the given currency in our 5296 // locale, and adjust the decimal digits and rounding for the 5297 // given currency. 5298 5299 super.setCurrency(theCurrency); 5300 if (theCurrency != null) { 5301 String s = theCurrency.getName(symbols.getULocale(), Currency.SYMBOL_NAME, null); 5302 symbols.setCurrency(theCurrency); 5303 symbols.setCurrencySymbol(s); 5304 } 5305 5306 if (currencySignCount != CURRENCY_SIGN_COUNT_ZERO) { 5307 if (theCurrency != null) { 5308 setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage)); 5309 int d = theCurrency.getDefaultFractionDigits(currencyUsage); 5310 setMinimumFractionDigits(d); 5311 setMaximumFractionDigits(d); 5312 } 5313 if (currencySignCount != CURRENCY_SIGN_COUNT_IN_PLURAL_FORMAT) { 5314 // This is not necessary for plural format type 5315 // because affixes will be resolved in subformat 5316 expandAffixes(null); 5317 } 5318 } 5319 } 5320 5321 /** 5322 * Sets the <tt>Currency Usage</tt> object used to display currency. 5323 * This takes effect immediately, if this format is a 5324 * currency format. 5325 * @param newUsage new currency context object to use. 5326 */ 5327 public void setCurrencyUsage(CurrencyUsage newUsage) { 5328 if (newUsage == null) { 5329 throw new NullPointerException("return value is null at method AAA"); 5330 } 5331 currencyUsage = newUsage; 5332 Currency theCurrency = this.getCurrency(); 5333 5334 // We set rounding/digit based on currency context 5335 if (theCurrency != null) { 5336 setRoundingIncrement(theCurrency.getRoundingIncrement(currencyUsage)); 5337 int d = theCurrency.getDefaultFractionDigits(currencyUsage); 5338 setMinimumFractionDigits(d); 5339 _setMaximumFractionDigits(d); 5340 } 5341 } 5342 5343 /** 5344 * Returns the <tt>Currency Usage</tt> object used to display currency 5345 */ 5346 public CurrencyUsage getCurrencyUsage() { 5347 return currencyUsage; 5348 } 5349 5350 /** 5351 * Returns the currency in effect for this formatter. Subclasses should override this 5352 * method as needed. Unlike getCurrency(), this method should never return null. 5353 * 5354 * @deprecated This API is ICU internal only. 5355 * @hide original deprecated declaration 5356 * @hide draft / provisional / internal are hidden on Android 5357 */ 5358 @Deprecated 5359 @Override 5360 protected Currency getEffectiveCurrency() { 5361 Currency c = getCurrency(); 5362 if (c == null) { 5363 c = Currency.getInstance(symbols.getInternationalCurrencySymbol()); 5364 } 5365 return c; 5366 } 5367 5368 /** 5369 * Sets the maximum number of digits allowed in the fraction portion of a number. This 5370 * override limits the fraction digit count to 340. 5371 * 5372 * @see NumberFormat#setMaximumFractionDigits 5373 */ 5374 @Override 5375 public void setMaximumFractionDigits(int newValue) { 5376 _setMaximumFractionDigits(newValue); 5377 resetActualRounding(); 5378 } 5379 5380 /* 5381 * Internal method for DecimalFormat, setting maximum fractional digits 5382 * without triggering actual rounding recalculated. 5383 */ 5384 private void _setMaximumFractionDigits(int newValue) { 5385 super.setMaximumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS)); 5386 } 5387 5388 /** 5389 * Sets the minimum number of digits allowed in the fraction portion of a number. This 5390 * override limits the fraction digit count to 340. 5391 * 5392 * @see NumberFormat#setMinimumFractionDigits 5393 */ 5394 @Override 5395 public void setMinimumFractionDigits(int newValue) { 5396 super.setMinimumFractionDigits(Math.min(newValue, DOUBLE_FRACTION_DIGITS)); 5397 } 5398 5399 /** 5400 * Sets whether {@link #parse(String, ParsePosition)} returns BigDecimal. The 5401 * default value is false. 5402 * 5403 * @param value true if {@link #parse(String, ParsePosition)} 5404 * returns BigDecimal. 5405 */ 5406 public void setParseBigDecimal(boolean value) { 5407 parseBigDecimal = value; 5408 } 5409 5410 /** 5411 * Returns whether {@link #parse(String, ParsePosition)} returns BigDecimal. 5412 * 5413 * @return true if {@link #parse(String, ParsePosition)} returns BigDecimal. 5414 */ 5415 public boolean isParseBigDecimal() { 5416 return parseBigDecimal; 5417 } 5418 5419 /** 5420 * Set the maximum number of exponent digits when parsing a number. 5421 * If the limit is set too high, an OutOfMemoryException may be triggered. 5422 * The default value is 1000. 5423 * @param newValue the new limit 5424 */ 5425 public void setParseMaxDigits(int newValue) { 5426 if (newValue > 0) { 5427 PARSE_MAX_EXPONENT = newValue; 5428 } 5429 } 5430 5431 /** 5432 * Get the current maximum number of exponent digits when parsing a 5433 * number. 5434 * @return the maximum number of exponent digits for parsing 5435 */ 5436 public int getParseMaxDigits() { 5437 return PARSE_MAX_EXPONENT; 5438 } 5439 5440 private void writeObject(ObjectOutputStream stream) throws IOException { 5441 // Ticket#6449 Format.Field instances are not serializable. When 5442 // formatToCharacterIterator is called, attributes (ArrayList) stores 5443 // FieldPosition instances with NumberFormat.Field. Because NumberFormat.Field is 5444 // not serializable, we need to clear the contents of the list when writeObject is 5445 // called. We could remove the field or make it transient, but it will break 5446 // serialization compatibility. 5447 attributes.clear(); 5448 5449 stream.defaultWriteObject(); 5450 } 5451 5452 /** 5453 * First, read the default serializable fields from the stream. Then if 5454 * <code>serialVersionOnStream</code> is less than 1, indicating that the stream was 5455 * written by JDK 1.1, initialize <code>useExponentialNotation</code> to false, since 5456 * it was not present in JDK 1.1. Finally, set serialVersionOnStream back to the 5457 * maximum allowed value so that default serialization will work properly if this 5458 * object is streamed out again. 5459 */ 5460 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 5461 stream.defaultReadObject(); 5462 5463 // Bug 4185761 validate fields [Richard/GCL] 5464 5465 // We only need to check the maximum counts because NumberFormat .readObject has 5466 // already ensured that the maximum is greater than the minimum count. 5467 5468 // Commented for compatibility with previous version, and reserved for further use 5469 // if (getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS || 5470 // getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { throw new 5471 // InvalidObjectException("Digit count out of range"); } 5472 5473 5474 // Android changed: Allow 2 billion integer digits. 5475 // Truncate the maximumIntegerDigits to MAX_INTEGER_DIGITS and 5476 // maximumFractionDigits to DOUBLE_FRACTION_DIGITS 5477 5478 if (getMaximumIntegerDigits() > MAX_INTEGER_DIGITS) { 5479 setMaximumIntegerDigits(MAX_INTEGER_DIGITS); 5480 } 5481 if (getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { 5482 _setMaximumFractionDigits(DOUBLE_FRACTION_DIGITS); 5483 } 5484 if (serialVersionOnStream < 2) { 5485 exponentSignAlwaysShown = false; 5486 setInternalRoundingIncrement(null); 5487 roundingMode = BigDecimal.ROUND_HALF_EVEN; 5488 formatWidth = 0; 5489 pad = ' '; 5490 padPosition = PAD_BEFORE_PREFIX; 5491 if (serialVersionOnStream < 1) { 5492 // Didn't have exponential fields 5493 useExponentialNotation = false; 5494 } 5495 } 5496 if (serialVersionOnStream < 3) { 5497 // Versions prior to 3 do not store a currency object. Create one to match 5498 // the DecimalFormatSymbols object. 5499 setCurrencyForSymbols(); 5500 } 5501 if (serialVersionOnStream < 4) { 5502 currencyUsage = CurrencyUsage.STANDARD; 5503 } 5504 serialVersionOnStream = currentSerialVersion; 5505 digitList = new DigitList(); 5506 5507 if (roundingIncrement != null) { 5508 setInternalRoundingIncrement(new BigDecimal(roundingIncrement)); 5509 } 5510 resetActualRounding(); 5511 } 5512 5513 private void setInternalRoundingIncrement(BigDecimal value) { 5514 roundingIncrementICU = value; 5515 roundingIncrement = value == null ? null : value.toBigDecimal(); 5516 } 5517 5518 // ---------------------------------------------------------------------- 5519 // INSTANCE VARIABLES 5520 // ---------------------------------------------------------------------- 5521 5522 private transient DigitList digitList = new DigitList(); 5523 5524 /** 5525 * The symbol used as a prefix when formatting positive numbers, e.g. "+". 5526 * 5527 * @serial 5528 * @see #getPositivePrefix 5529 */ 5530 private String positivePrefix = ""; 5531 5532 /** 5533 * The symbol used as a suffix when formatting positive numbers. This is often an 5534 * empty string. 5535 * 5536 * @serial 5537 * @see #getPositiveSuffix 5538 */ 5539 private String positiveSuffix = ""; 5540 5541 /** 5542 * The symbol used as a prefix when formatting negative numbers, e.g. "-". 5543 * 5544 * @serial 5545 * @see #getNegativePrefix 5546 */ 5547 private String negativePrefix = "-"; 5548 5549 /** 5550 * The symbol used as a suffix when formatting negative numbers. This is often an 5551 * empty string. 5552 * 5553 * @serial 5554 * @see #getNegativeSuffix 5555 */ 5556 private String negativeSuffix = ""; 5557 5558 /** 5559 * The prefix pattern for non-negative numbers. This variable corresponds to 5560 * <code>positivePrefix</code>. 5561 * 5562 * <p>This pattern is expanded by the method <code>expandAffix()</code> to 5563 * <code>positivePrefix</code> to update the latter to reflect changes in 5564 * <code>symbols</code>. If this variable is <code>null</code> then 5565 * <code>positivePrefix</code> is taken as a literal value that does not change when 5566 * <code>symbols</code> changes. This variable is always <code>null</code> for 5567 * <code>DecimalFormat</code> objects older than stream version 2 restored from 5568 * stream. 5569 * 5570 * @serial 5571 */ 5572 // [Richard/GCL] 5573 private String posPrefixPattern; 5574 5575 /** 5576 * The suffix pattern for non-negative numbers. This variable corresponds to 5577 * <code>positiveSuffix</code>. This variable is analogous to 5578 * <code>posPrefixPattern</code>; see that variable for further documentation. 5579 * 5580 * @serial 5581 */ 5582 // [Richard/GCL] 5583 private String posSuffixPattern; 5584 5585 /** 5586 * The prefix pattern for negative numbers. This variable corresponds to 5587 * <code>negativePrefix</code>. This variable is analogous to 5588 * <code>posPrefixPattern</code>; see that variable for further documentation. 5589 * 5590 * @serial 5591 */ 5592 // [Richard/GCL] 5593 private String negPrefixPattern; 5594 5595 /** 5596 * The suffix pattern for negative numbers. This variable corresponds to 5597 * <code>negativeSuffix</code>. This variable is analogous to 5598 * <code>posPrefixPattern</code>; see that variable for further documentation. 5599 * 5600 * @serial 5601 */ 5602 // [Richard/GCL] 5603 private String negSuffixPattern; 5604 5605 /** 5606 * Formatter for ChoiceFormat-based currency names. If this field is not null, then 5607 * delegate to it to format currency symbols. 5608 * TODO: This is obsolete: Remove, and design extensible serialization. ICU ticket #12090. 5609 */ 5610 private ChoiceFormat currencyChoice; 5611 5612 /** 5613 * The multiplier for use in percent, permill, etc. 5614 * 5615 * @serial 5616 * @see #getMultiplier 5617 */ 5618 private int multiplier = 1; 5619 5620 /** 5621 * The number of digits between grouping separators in the integer portion of a 5622 * number. Must be greater than 0 if <code>NumberFormat.groupingUsed</code> is true. 5623 * 5624 * @serial 5625 * @see #getGroupingSize 5626 * @see NumberFormat#isGroupingUsed 5627 */ 5628 private byte groupingSize = 3; // invariant, > 0 if useThousands 5629 5630 /** 5631 * The secondary grouping size. This is only used for Hindi numerals, which use a 5632 * primary grouping of 3 and a secondary grouping of 2, e.g., "12,34,567". If this 5633 * value is less than 1, then secondary grouping is equal to the primary grouping. 5634 * 5635 */ 5636 private byte groupingSize2 = 0; 5637 5638 /** 5639 * If true, forces the decimal separator to always appear in a formatted number, even 5640 * if the fractional part of the number is zero. 5641 * 5642 * @serial 5643 * @see #isDecimalSeparatorAlwaysShown 5644 */ 5645 private boolean decimalSeparatorAlwaysShown = false; 5646 5647 /** 5648 * The <code>DecimalFormatSymbols</code> object used by this format. It contains the 5649 * symbols used to format numbers, e.g. the grouping separator, decimal separator, and 5650 * so on. 5651 * 5652 * @serial 5653 * @see #setDecimalFormatSymbols 5654 * @see DecimalFormatSymbols 5655 */ 5656 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); 5657 5658 /** 5659 * True to use significant digits rather than integer and fraction digit counts. 5660 * 5661 * @serial 5662 */ 5663 private boolean useSignificantDigits = false; 5664 5665 /** 5666 * The minimum number of significant digits to show. Must be >= 1 and <= 5667 * maxSignificantDigits. Ignored unless useSignificantDigits == true. 5668 * 5669 * @serial 5670 */ 5671 private int minSignificantDigits = 1; 5672 5673 /** 5674 * The maximum number of significant digits to show. Must be >= 5675 * minSignficantDigits. Ignored unless useSignificantDigits == true. 5676 * 5677 * @serial 5678 */ 5679 private int maxSignificantDigits = 6; 5680 5681 /** 5682 * True to force the use of exponential (i.e. scientific) notation 5683 * when formatting numbers. 5684 * 5685 *<p> Note that the JDK 1.2 public API provides no way to set this 5686 * field, even though it is supported by the implementation and 5687 * the stream format. The intent is that this will be added to the 5688 * API in the future. 5689 * 5690 * @serial 5691 */ 5692 private boolean useExponentialNotation; // Newly persistent in JDK 1.2 5693 5694 /** 5695 * The minimum number of digits used to display the exponent when a number is 5696 * formatted in exponential notation. This field is ignored if 5697 * <code>useExponentialNotation</code> is not true. 5698 * 5699 * <p>Note that the JDK 1.2 public API provides no way to set this field, even though 5700 * it is supported by the implementation and the stream format. The intent is that 5701 * this will be added to the API in the future. 5702 * 5703 * @serial 5704 */ 5705 private byte minExponentDigits; // Newly persistent in JDK 1.2 5706 5707 /** 5708 * If true, the exponent is always prefixed with either the plus sign or the minus 5709 * sign. Otherwise, only negative exponents are prefixed with the minus sign. This has 5710 * no effect unless <code>useExponentialNotation</code> is true. 5711 * 5712 * @serial 5713 */ 5714 private boolean exponentSignAlwaysShown = false; 5715 5716 /** 5717 * The value to which numbers are rounded during formatting. For example, if the 5718 * rounding increment is 0.05, then 13.371 would be formatted as 13.350, assuming 3 5719 * fraction digits. Has the value <code>null</code> if rounding is not in effect, or a 5720 * positive value if rounding is in effect. Default value <code>null</code>. 5721 * 5722 * @serial 5723 */ 5724 // Note: this is kept in sync with roundingIncrementICU. 5725 // it is only kept around to avoid a conversion when formatting a java.math.BigDecimal 5726 private java.math.BigDecimal roundingIncrement = null; 5727 5728 /** 5729 * The value to which numbers are rounded during formatting. For example, if the 5730 * rounding increment is 0.05, then 13.371 would be formatted as 13.350, assuming 3 5731 * fraction digits. Has the value <code>null</code> if rounding is not in effect, or a 5732 * positive value if rounding is in effect. Default value <code>null</code>. WARNING: 5733 * the roundingIncrement value is the one serialized. 5734 * 5735 * @serial 5736 */ 5737 private transient BigDecimal roundingIncrementICU = null; 5738 5739 /** 5740 * The rounding mode. This value controls any rounding operations which occur when 5741 * applying a rounding increment or when reducing the number of fraction digits to 5742 * satisfy a maximum fraction digits limit. The value may assume any of the 5743 * <code>BigDecimal</code> rounding mode values. Default value 5744 * <code>BigDecimal.ROUND_HALF_EVEN</code>. 5745 * 5746 * @serial 5747 */ 5748 private int roundingMode = BigDecimal.ROUND_HALF_EVEN; 5749 5750 /** 5751 * Operations on <code>BigDecimal</code> numbers are controlled by a {@link 5752 * MathContext} object, which provides the context (precision and other information) 5753 * for the operation. The default <code>MathContext</code> settings are 5754 * <code>digits=0, form=PLAIN, lostDigits=false, roundingMode=ROUND_HALF_UP</code>; 5755 * these settings perform fixed point arithmetic with unlimited precision, as defined 5756 * for the original BigDecimal class in Java 1.1 and Java 1.2 5757 */ 5758 // context for plain unlimited math 5759 private MathContext mathContext = new MathContext(0, MathContext.PLAIN); 5760 5761 /** 5762 * The padded format width, or zero if there is no padding. Must be >= 0. Default 5763 * value zero. 5764 * 5765 * @serial 5766 */ 5767 private int formatWidth = 0; 5768 5769 /** 5770 * The character used to pad the result of format to <code>formatWidth</code>, if 5771 * padding is in effect. Default value ' '. 5772 * 5773 * @serial 5774 */ 5775 private char pad = ' '; 5776 5777 /** 5778 * The position in the string at which the <code>pad</code> character will be 5779 * inserted, if padding is in effect. Must have a value from 5780 * <code>PAD_BEFORE_PREFIX</code> to <code>PAD_AFTER_SUFFIX</code>. Default value 5781 * <code>PAD_BEFORE_PREFIX</code>. 5782 * 5783 * @serial 5784 */ 5785 private int padPosition = PAD_BEFORE_PREFIX; 5786 5787 /** 5788 * True if {@link #parse(String, ParsePosition)} to return BigDecimal rather than 5789 * Long, Double or BigDecimal except special values. This property is introduced for 5790 * J2SE 5 compatibility support. 5791 * 5792 * @serial 5793 * @see #setParseBigDecimal(boolean) 5794 * @see #isParseBigDecimal() 5795 */ 5796 private boolean parseBigDecimal = false; 5797 5798 /** 5799 * The currency usage for the NumberFormat(standard or cash usage). 5800 * It is used as STANDARD by default 5801 */ 5802 private CurrencyUsage currencyUsage = CurrencyUsage.STANDARD; 5803 5804 // ---------------------------------------------------------------------- 5805 5806 static final int currentSerialVersion = 4; 5807 5808 /** 5809 * The internal serial version which says which version was written Possible values 5810 * are: 5811 * 5812 * <ul> 5813 * 5814 * <li><b>0</b> (default): versions before JDK 1.2 5815 * 5816 * <li><b>1</b>: version from JDK 1.2 and later, which includes the two new fields 5817 * <code>useExponentialNotation</code> and <code>minExponentDigits</code>. 5818 * 5819 * <li><b>2</b>: version on AlphaWorks, which adds roundingMode, formatWidth, pad, 5820 * padPosition, exponentSignAlwaysShown, roundingIncrement. 5821 * 5822 * <li><b>3</b>: ICU 2.2. Adds currency object. 5823 * 5824 * <li><b>4</b>: ICU 54. Adds currency usage(standard vs cash) 5825 * 5826 * </ul> 5827 * 5828 * @serial 5829 */ 5830 private int serialVersionOnStream = currentSerialVersion; 5831 5832 // ---------------------------------------------------------------------- 5833 // CONSTANTS 5834 // ---------------------------------------------------------------------- 5835 5836 /** 5837 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to 5838 * specify pad characters inserted before the prefix. 5839 * 5840 * @see #setPadPosition 5841 * @see #getPadPosition 5842 * @see #PAD_AFTER_PREFIX 5843 * @see #PAD_BEFORE_SUFFIX 5844 * @see #PAD_AFTER_SUFFIX 5845 */ 5846 public static final int PAD_BEFORE_PREFIX = 0; 5847 5848 /** 5849 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to 5850 * specify pad characters inserted after the prefix. 5851 * 5852 * @see #setPadPosition 5853 * @see #getPadPosition 5854 * @see #PAD_BEFORE_PREFIX 5855 * @see #PAD_BEFORE_SUFFIX 5856 * @see #PAD_AFTER_SUFFIX 5857 */ 5858 public static final int PAD_AFTER_PREFIX = 1; 5859 5860 /** 5861 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to 5862 * specify pad characters inserted before the suffix. 5863 * 5864 * @see #setPadPosition 5865 * @see #getPadPosition 5866 * @see #PAD_BEFORE_PREFIX 5867 * @see #PAD_AFTER_PREFIX 5868 * @see #PAD_AFTER_SUFFIX 5869 */ 5870 public static final int PAD_BEFORE_SUFFIX = 2; 5871 5872 /** 5873 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to 5874 * specify pad characters inserted after the suffix. 5875 * 5876 * @see #setPadPosition 5877 * @see #getPadPosition 5878 * @see #PAD_BEFORE_PREFIX 5879 * @see #PAD_AFTER_PREFIX 5880 * @see #PAD_BEFORE_SUFFIX 5881 */ 5882 public static final int PAD_AFTER_SUFFIX = 3; 5883 5884 // Constants for characters used in programmatic (unlocalized) patterns. 5885 static final char PATTERN_ZERO_DIGIT = '0'; 5886 static final char PATTERN_ONE_DIGIT = '1'; 5887 static final char PATTERN_TWO_DIGIT = '2'; 5888 static final char PATTERN_THREE_DIGIT = '3'; 5889 static final char PATTERN_FOUR_DIGIT = '4'; 5890 static final char PATTERN_FIVE_DIGIT = '5'; 5891 static final char PATTERN_SIX_DIGIT = '6'; 5892 static final char PATTERN_SEVEN_DIGIT = '7'; 5893 static final char PATTERN_EIGHT_DIGIT = '8'; 5894 static final char PATTERN_NINE_DIGIT = '9'; 5895 static final char PATTERN_GROUPING_SEPARATOR = ','; 5896 static final char PATTERN_DECIMAL_SEPARATOR = '.'; 5897 static final char PATTERN_DIGIT = '#'; 5898 static final char PATTERN_SIGNIFICANT_DIGIT = '@'; 5899 static final char PATTERN_EXPONENT = 'E'; 5900 static final char PATTERN_PLUS_SIGN = '+'; 5901 static final char PATTERN_MINUS_SIGN = '-'; 5902 5903 // Affix 5904 private static final char PATTERN_PER_MILLE = '\u2030'; 5905 private static final char PATTERN_PERCENT = '%'; 5906 static final char PATTERN_PAD_ESCAPE = '*'; 5907 5908 // Other 5909 private static final char PATTERN_SEPARATOR = ';'; 5910 5911 // Pad escape is package private to allow access by DecimalFormatSymbols. 5912 // Also plus sign. Also exponent. 5913 5914 /** 5915 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It is used in 5916 * patterns and substitued with either the currency symbol, or if it is doubled, with 5917 * the international currency symbol. If the CURRENCY_SIGN is seen in a pattern, then 5918 * the decimal separator is replaced with the monetary decimal separator. 5919 * 5920 * The CURRENCY_SIGN is not localized. 5921 */ 5922 private static final char CURRENCY_SIGN = '\u00A4'; 5923 5924 private static final char QUOTE = '\''; 5925 5926 /** 5927 * Upper limit on integer and fraction digits for a Java double [Richard/GCL] 5928 */ 5929 static final int DOUBLE_INTEGER_DIGITS = 309; 5930 // Android changed: Allow 2 billion integer digits. 5931 // This change is necessary to stay feature-compatible in java.text.DecimalFormat which 5932 // used to be implemented using ICU4C (which has a 2 billion integer digits limit) and 5933 // is now implemented based on this class. 5934 static final int MAX_INTEGER_DIGITS = 2000000000; 5935 static final int DOUBLE_FRACTION_DIGITS = 340; 5936 5937 /** 5938 * When someone turns on scientific mode, we assume that more than this number of 5939 * digits is due to flipping from some other mode that didn't restrict the maximum, 5940 * and so we force 1 integer digit. We don't bother to track and see if someone is 5941 * using exponential notation with more than this number, it wouldn't make sense 5942 * anyway, and this is just to make sure that someone turning on scientific mode with 5943 * default settings doesn't end up with lots of zeroes. 5944 */ 5945 static final int MAX_SCIENTIFIC_INTEGER_DIGITS = 8; 5946 5947 // Proclaim JDK 1.1 serial compatibility. 5948 private static final long serialVersionUID = 864413376551465018L; 5949 5950 private ArrayList<FieldPosition> attributes = new ArrayList<FieldPosition>(); 5951 5952 // The following are used in currency format 5953 5954 // -- triple currency sign char array 5955 // private static final char[] tripleCurrencySign = {0xA4, 0xA4, 0xA4}; 5956 // -- triple currency sign string 5957 // private static final String tripleCurrencyStr = new String(tripleCurrencySign); 5958 // 5959 // -- default currency plural pattern char array 5960 // private static final char[] defaultCurrencyPluralPatternChar = 5961 // {0, '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4}; 5962 // -- default currency plural pattern string 5963 // private static final String defaultCurrencyPluralPattern = 5964 // new String(defaultCurrencyPluralPatternChar); 5965 5966 // pattern used in this formatter 5967 private String formatPattern = ""; 5968 // style is only valid when decimal formatter is constructed by 5969 // DecimalFormat(pattern, decimalFormatSymbol, style) 5970 private int style = NumberFormat.NUMBERSTYLE; 5971 /** 5972 * Represents whether this is a currency format, and which currency format style. 0: 5973 * not currency format type; 1: currency style -- symbol name, such as "$" for US 5974 * dollar. 2: currency style -- ISO name, such as USD for US dollar. 3: currency style 5975 * -- plural long name, such as "US Dollar" for "1.00 US Dollar", or "US Dollars" for 5976 * "3.00 US Dollars". 5977 */ 5978 private int currencySignCount = CURRENCY_SIGN_COUNT_ZERO; 5979 5980 /** 5981 * For parsing purposes, we need to remember all prefix patterns and suffix patterns 5982 * of every currency format pattern, including the pattern of the default currency 5983 * style, ISO currency style, and plural currency style. The patterns are set through 5984 * applyPattern. The following are used to represent the affix patterns in currency 5985 * plural formats. 5986 */ 5987 private static final class AffixForCurrency { 5988 // negative prefix pattern 5989 private String negPrefixPatternForCurrency = null; 5990 // negative suffix pattern 5991 private String negSuffixPatternForCurrency = null; 5992 // positive prefix pattern 5993 private String posPrefixPatternForCurrency = null; 5994 // positive suffix pattern 5995 private String posSuffixPatternForCurrency = null; 5996 private final int patternType; 5997 5998 public AffixForCurrency(String negPrefix, String negSuffix, String posPrefix, 5999 String posSuffix, int type) { 6000 negPrefixPatternForCurrency = negPrefix; 6001 negSuffixPatternForCurrency = negSuffix; 6002 posPrefixPatternForCurrency = posPrefix; 6003 posSuffixPatternForCurrency = posSuffix; 6004 patternType = type; 6005 } 6006 6007 public String getNegPrefix() { 6008 return negPrefixPatternForCurrency; 6009 } 6010 6011 public String getNegSuffix() { 6012 return negSuffixPatternForCurrency; 6013 } 6014 6015 public String getPosPrefix() { 6016 return posPrefixPatternForCurrency; 6017 } 6018 6019 public String getPosSuffix() { 6020 return posSuffixPatternForCurrency; 6021 } 6022 6023 public int getPatternType() { 6024 return patternType; 6025 } 6026 } 6027 6028 // Affix pattern set for currency. It is a set of AffixForCurrency, each element of 6029 // the set saves the negative prefix, negative suffix, positive prefix, and positive 6030 // suffix of a pattern. 6031 private transient Set<AffixForCurrency> affixPatternsForCurrency = null; 6032 6033 // For currency parsing. Since currency parsing needs to parse against all currency 6034 // patterns, before the parsing, we need to set up the affix patterns for all currencies. 6035 private transient boolean isReadyForParsing = false; 6036 6037 // Information needed for DecimalFormat to format/parse currency plural. 6038 private CurrencyPluralInfo currencyPluralInfo = null; 6039 6040 /** 6041 * Unit is an immutable class for the textual representation of a unit, in 6042 * particular its prefix and suffix. 6043 * 6044 * @author rocketman 6045 * 6046 */ 6047 static class Unit { 6048 private final String prefix; 6049 private final String suffix; 6050 6051 public Unit(String prefix, String suffix) { 6052 this.prefix = prefix; 6053 this.suffix = suffix; 6054 } 6055 6056 public void writeSuffix(StringBuffer toAppendTo) { 6057 toAppendTo.append(suffix); 6058 } 6059 6060 public void writePrefix(StringBuffer toAppendTo) { 6061 toAppendTo.append(prefix); 6062 } 6063 6064 @Override 6065 public boolean equals(Object obj) { 6066 if (this == obj) { 6067 return true; 6068 } 6069 if (!(obj instanceof Unit)) { 6070 return false; 6071 } 6072 Unit other = (Unit) obj; 6073 return prefix.equals(other.prefix) && suffix.equals(other.suffix); 6074 } 6075 @Override 6076 public String toString() { 6077 return prefix + "/" + suffix; 6078 } 6079 } 6080 6081 static final Unit NULL_UNIT = new Unit("", ""); 6082 6083 // Note about rounding implementation 6084 // 6085 // The original design intended to skip rounding operation when roundingIncrement is not 6086 // set. However, rounding may need to occur when fractional digits exceed the width of 6087 // fractional part of pattern. 6088 // 6089 // DigitList class has built-in rounding mechanism, using ROUND_HALF_EVEN. This implementation 6090 // forces non-null roundingIncrement if the setting is other than ROUND_HALF_EVEN, otherwise, 6091 // when rounding occurs in DigitList by pattern's fractional digits' width, the result 6092 // does not match the rounding mode. 6093 // 6094 // Ideally, all rounding operation should be done in one place like ICU4C trunk does 6095 // (ICU4C rounding implementation was rewritten recently). This is intrim implemetation 6096 // to fix various issues. In the future, we should entire implementation of rounding 6097 // in this class, like ICU4C did. 6098 // 6099 // Once we fully implement rounding logic in DigitList, then following fields and methods 6100 // should be gone. 6101 6102 private transient BigDecimal actualRoundingIncrementICU = null; 6103 private transient java.math.BigDecimal actualRoundingIncrement = null; 6104 6105 /* 6106 * The actual rounding increment as a double. 6107 */ 6108 private transient double roundingDouble = 0.0; 6109 6110 /* 6111 * If the roundingDouble is the reciprocal of an integer (the most common case!), this 6112 * is set to be that integer. Otherwise it is 0.0. 6113 */ 6114 private transient double roundingDoubleReciprocal = 0.0; 6115 6116 /* 6117 * Set roundingDouble, roundingDoubleReciprocal and actualRoundingIncrement 6118 * based on rounding mode and width of fractional digits. Whenever setting affecting 6119 * rounding mode, rounding increment and maximum width of fractional digits, then 6120 * this method must be called. 6121 * 6122 * roundingIncrementICU is the field storing the custom rounding increment value, 6123 * while actual rounding increment could be larger. 6124 */ 6125 private void resetActualRounding() { 6126 if (roundingIncrementICU != null) { 6127 BigDecimal byWidth = getMaximumFractionDigits() > 0 ? 6128 BigDecimal.ONE.movePointLeft(getMaximumFractionDigits()) : BigDecimal.ONE; 6129 if (roundingIncrementICU.compareTo(byWidth) >= 0) { 6130 actualRoundingIncrementICU = roundingIncrementICU; 6131 } else { 6132 actualRoundingIncrementICU = byWidth.equals(BigDecimal.ONE) ? null : byWidth; 6133 } 6134 } else { 6135 if (roundingMode == BigDecimal.ROUND_HALF_EVEN || isScientificNotation()) { 6136 // This rounding fix is irrelevant if mode is ROUND_HALF_EVEN as DigitList 6137 // does ROUND_HALF_EVEN for us. This rounding fix won't work at all for 6138 // scientific notation. 6139 actualRoundingIncrementICU = null; 6140 } else { 6141 if (getMaximumFractionDigits() > 0) { 6142 actualRoundingIncrementICU = BigDecimal.ONE.movePointLeft(getMaximumFractionDigits()); 6143 } else { 6144 actualRoundingIncrementICU = BigDecimal.ONE; 6145 } 6146 } 6147 } 6148 6149 if (actualRoundingIncrementICU == null) { 6150 setRoundingDouble(0.0d); 6151 actualRoundingIncrement = null; 6152 } else { 6153 setRoundingDouble(actualRoundingIncrementICU.doubleValue()); 6154 actualRoundingIncrement = actualRoundingIncrementICU.toBigDecimal(); 6155 } 6156 } 6157 6158 static final double roundingIncrementEpsilon = 0.000000001; 6159 6160 private void setRoundingDouble(double newValue) { 6161 roundingDouble = newValue; 6162 if (roundingDouble > 0.0d) { 6163 double rawRoundedReciprocal = 1.0d / roundingDouble; 6164 roundingDoubleReciprocal = Math.rint(rawRoundedReciprocal); 6165 if (Math.abs(rawRoundedReciprocal - roundingDoubleReciprocal) > roundingIncrementEpsilon) { 6166 roundingDoubleReciprocal = 0.0d; 6167 } 6168 } else { 6169 roundingDoubleReciprocal = 0.0d; 6170 } 6171 } 6172} 6173 6174// eof 6175