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