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