jtulach@1334: /* jtulach@1334: * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. jtulach@1334: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jtulach@1334: * jtulach@1334: * This code is free software; you can redistribute it and/or modify it jtulach@1334: * under the terms of the GNU General Public License version 2 only, as jtulach@1334: * published by the Free Software Foundation. Oracle designates this jtulach@1334: * particular file as subject to the "Classpath" exception as provided jtulach@1334: * by Oracle in the LICENSE file that accompanied this code. jtulach@1334: * jtulach@1334: * This code is distributed in the hope that it will be useful, but WITHOUT jtulach@1334: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jtulach@1334: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jtulach@1334: * version 2 for more details (a copy is included in the LICENSE file that jtulach@1334: * accompanied this code). jtulach@1334: * jtulach@1334: * You should have received a copy of the GNU General Public License version jtulach@1334: * 2 along with this work; if not, write to the Free Software Foundation, jtulach@1334: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jtulach@1334: * jtulach@1334: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jtulach@1334: * or visit www.oracle.com if you need additional information or have any jtulach@1334: * questions. jtulach@1334: */ jtulach@1334: jtulach@1334: /* jtulach@1334: * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved jtulach@1334: * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved jtulach@1334: * jtulach@1334: * The original version of this source code and documentation is copyrighted jtulach@1334: * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These jtulach@1334: * materials are provided under terms of a License Agreement between Taligent jtulach@1334: * and Sun. This technology is protected by multiple US and International jtulach@1334: * patents. This notice and attribution to Taligent may not be removed. jtulach@1334: * Taligent is a registered trademark of Taligent, Inc. jtulach@1334: * jtulach@1334: */ jtulach@1334: jtulach@1334: package java.text; jtulach@1334: jtulach@1334: import java.io.InvalidObjectException; jtulach@1334: import java.io.IOException; jtulach@1334: import java.io.ObjectInputStream; jtulach@1334: import java.math.BigDecimal; jtulach@1334: import java.math.BigInteger; jtulach@1334: import java.math.RoundingMode; jtulach@1334: import java.util.ArrayList; jtulach@1334: import java.util.Currency; jtulach@1334: import java.util.Locale; jtulach@1334: import java.util.ResourceBundle; jtulach@1334: import java.util.concurrent.ConcurrentHashMap; jtulach@1334: import java.util.concurrent.ConcurrentMap; jtulach@1334: import java.util.concurrent.atomic.AtomicInteger; jtulach@1334: import java.util.concurrent.atomic.AtomicLong; jtulach@1334: import sun.util.resources.LocaleData; jtulach@1334: jtulach@1334: /** jtulach@1334: * DecimalFormat is a concrete subclass of jtulach@1334: * NumberFormat that formats decimal numbers. It has a variety of jtulach@1334: * features designed to make it possible to parse and format numbers in any jtulach@1334: * locale, including support for Western, Arabic, and Indic digits. It also jtulach@1334: * supports different kinds of numbers, including integers (123), fixed-point jtulach@1334: * numbers (123.4), scientific notation (1.23E4), percentages (12%), and jtulach@1334: * currency amounts ($123). All of these can be localized. jtulach@1334: * jtulach@1334: *

To obtain a NumberFormat for a specific locale, including the jtulach@1334: * default locale, call one of NumberFormat's factory methods, such jtulach@1334: * as getInstance(). In general, do not call the jtulach@1334: * DecimalFormat constructors directly, since the jtulach@1334: * NumberFormat factory methods may return subclasses other than jtulach@1334: * DecimalFormat. If you need to customize the format object, do jtulach@1334: * something like this: jtulach@1334: * jtulach@1334: *

jtulach@1334:  * NumberFormat f = NumberFormat.getInstance(loc);
jtulach@1334:  * if (f instanceof DecimalFormat) {
jtulach@1334:  *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
jtulach@1334:  * }
jtulach@1334:  * 
jtulach@1334: * jtulach@1334: *

A DecimalFormat comprises a pattern and a set of jtulach@1334: * symbols. The pattern may be set directly using jtulach@1334: * applyPattern(), or indirectly using the API methods. The jtulach@1334: * symbols are stored in a DecimalFormatSymbols object. When using jtulach@1334: * the NumberFormat factory methods, the pattern and symbols are jtulach@1334: * read from localized ResourceBundles. jtulach@1334: * jtulach@1334: *

Patterns

jtulach@1334: * jtulach@1334: * DecimalFormat patterns have the following syntax: jtulach@1334: *
jtulach@1334:  * Pattern:
jtulach@1334:  *         PositivePattern
jtulach@1334:  *         PositivePattern ; NegativePattern
jtulach@1334:  * PositivePattern:
jtulach@1334:  *         Prefixopt Number Suffixopt
jtulach@1334:  * NegativePattern:
jtulach@1334:  *         Prefixopt Number Suffixopt
jtulach@1334:  * Prefix:
jtulach@1334:  *         any Unicode characters except \uFFFE, \uFFFF, and special characters
jtulach@1334:  * Suffix:
jtulach@1334:  *         any Unicode characters except \uFFFE, \uFFFF, and special characters
jtulach@1334:  * Number:
jtulach@1334:  *         Integer Exponentopt
jtulach@1334:  *         Integer . Fraction Exponentopt
jtulach@1334:  * Integer:
jtulach@1334:  *         MinimumInteger
jtulach@1334:  *         #
jtulach@1334:  *         # Integer
jtulach@1334:  *         # , Integer
jtulach@1334:  * MinimumInteger:
jtulach@1334:  *         0
jtulach@1334:  *         0 MinimumInteger
jtulach@1334:  *         0 , MinimumInteger
jtulach@1334:  * Fraction:
jtulach@1334:  *         MinimumFractionopt OptionalFractionopt
jtulach@1334:  * MinimumFraction:
jtulach@1334:  *         0 MinimumFractionopt
jtulach@1334:  * OptionalFraction:
jtulach@1334:  *         # OptionalFractionopt
jtulach@1334:  * Exponent:
jtulach@1334:  *         E MinimumExponent
jtulach@1334:  * MinimumExponent:
jtulach@1334:  *         0 MinimumExponentopt
jtulach@1334:  * 
jtulach@1334: * jtulach@1334: *

A DecimalFormat pattern contains a positive and negative jtulach@1334: * subpattern, for example, "#,##0.00;(#,##0.00)". Each jtulach@1334: * subpattern has a prefix, numeric part, and suffix. The negative subpattern jtulach@1334: * is optional; if absent, then the positive subpattern prefixed with the jtulach@1334: * localized minus sign ('-' in most locales) is used as the jtulach@1334: * negative subpattern. That is, "0.00" alone is equivalent to jtulach@1334: * "0.00;-0.00". If there is an explicit negative subpattern, it jtulach@1334: * serves only to specify the negative prefix and suffix; the number of digits, jtulach@1334: * minimal digits, and other characteristics are all the same as the positive jtulach@1334: * pattern. That means that "#,##0.0#;(#)" produces precisely jtulach@1334: * the same behavior as "#,##0.0#;(#,##0.0#)". jtulach@1334: * jtulach@1334: *

The prefixes, suffixes, and various symbols used for infinity, digits, jtulach@1334: * thousands separators, decimal separators, etc. may be set to arbitrary jtulach@1334: * values, and they will appear properly during formatting. However, care must jtulach@1334: * be taken that the symbols and strings do not conflict, or parsing will be jtulach@1334: * unreliable. For example, either the positive and negative prefixes or the jtulach@1334: * suffixes must be distinct for DecimalFormat.parse() to be able jtulach@1334: * to distinguish positive from negative values. (If they are identical, then jtulach@1334: * DecimalFormat will behave as if no negative subpattern was jtulach@1334: * specified.) Another example is that the decimal separator and thousands jtulach@1334: * separator should be distinct characters, or parsing will be impossible. jtulach@1334: * jtulach@1334: *

The grouping separator is commonly used for thousands, but in some jtulach@1334: * countries it separates ten-thousands. The grouping size is a constant number jtulach@1334: * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for jtulach@1334: * 1,0000,0000. If you supply a pattern with multiple grouping characters, the jtulach@1334: * interval between the last one and the end of the integer is the one that is jtulach@1334: * used. So "#,##,###,####" == "######,####" == jtulach@1334: * "##,####,####". jtulach@1334: * jtulach@1334: *

Special Pattern Characters

jtulach@1334: * jtulach@1334: *

Many characters in a pattern are taken literally; they are matched during jtulach@1334: * parsing and output unchanged during formatting. Special characters, on the jtulach@1334: * other hand, stand for other characters, strings, or classes of characters. jtulach@1334: * They must be quoted, unless noted otherwise, if they are to appear in the jtulach@1334: * prefix or suffix as literals. jtulach@1334: * jtulach@1334: *

The characters listed here are used in non-localized patterns. Localized jtulach@1334: * patterns use the corresponding characters taken from this formatter's jtulach@1334: * DecimalFormatSymbols object instead, and these characters lose jtulach@1334: * their special status. Two exceptions are the currency sign and quote, which jtulach@1334: * are not localized. jtulach@1334: * jtulach@1334: *

jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: * jtulach@1334: *
Symbol jtulach@1334: * Location jtulach@1334: * Localized? jtulach@1334: * Meaning jtulach@1334: *
0 jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Digit jtulach@1334: *
# jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Digit, zero shows as absent jtulach@1334: *
. jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Decimal separator or monetary decimal separator jtulach@1334: *
- jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Minus sign jtulach@1334: *
, jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Grouping separator jtulach@1334: *
E jtulach@1334: * Number jtulach@1334: * Yes jtulach@1334: * Separates mantissa and exponent in scientific notation. jtulach@1334: * Need not be quoted in prefix or suffix. jtulach@1334: *
; jtulach@1334: * Subpattern boundary jtulach@1334: * Yes jtulach@1334: * Separates positive and negative subpatterns jtulach@1334: *
% jtulach@1334: * Prefix or suffix jtulach@1334: * Yes jtulach@1334: * Multiply by 100 and show as percentage jtulach@1334: *
\u2030 jtulach@1334: * Prefix or suffix jtulach@1334: * Yes jtulach@1334: * Multiply by 1000 and show as per mille value jtulach@1334: *
¤ (\u00A4) jtulach@1334: * Prefix or suffix jtulach@1334: * No jtulach@1334: * Currency sign, replaced by currency symbol. If jtulach@1334: * doubled, replaced by international currency symbol. jtulach@1334: * If present in a pattern, the monetary decimal separator jtulach@1334: * is used instead of the decimal separator. jtulach@1334: *
' jtulach@1334: * Prefix or suffix jtulach@1334: * No jtulach@1334: * Used to quote special characters in a prefix or suffix, jtulach@1334: * for example, "'#'#" formats 123 to jtulach@1334: * "#123". To create a single quote jtulach@1334: * itself, use two in a row: "# o''clock". jtulach@1334: *
jtulach@1334: *
jtulach@1334: * jtulach@1334: *

Scientific Notation

jtulach@1334: * jtulach@1334: *

Numbers in scientific notation are expressed as the product of a mantissa jtulach@1334: * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The jtulach@1334: * mantissa is often in the range 1.0 <= x < 10.0, but it need not be. jtulach@1334: * DecimalFormat can be instructed to format and parse scientific jtulach@1334: * notation only via a pattern; there is currently no factory method jtulach@1334: * that creates a scientific notation format. In a pattern, the exponent jtulach@1334: * character immediately followed by one or more digit characters indicates jtulach@1334: * scientific notation. Example: "0.###E0" formats the number jtulach@1334: * 1234 as "1.234E3". jtulach@1334: * jtulach@1334: *

jtulach@1334: * jtulach@1334: *

Rounding

jtulach@1334: * jtulach@1334: * DecimalFormat provides rounding modes defined in jtulach@1334: * {@link java.math.RoundingMode} for formatting. By default, it uses jtulach@1334: * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}. jtulach@1334: * jtulach@1334: *

Digits

jtulach@1334: * jtulach@1334: * For formatting, DecimalFormat uses the ten consecutive jtulach@1334: * characters starting with the localized zero digit defined in the jtulach@1334: * DecimalFormatSymbols object as digits. For parsing, these jtulach@1334: * digits as well as all Unicode decimal digits, as defined by jtulach@1334: * {@link Character#digit Character.digit}, are recognized. jtulach@1334: * jtulach@1334: *

Special Values

jtulach@1334: * jtulach@1334: *

NaN is formatted as a string, which typically has a single character jtulach@1334: * \uFFFD. This string is determined by the jtulach@1334: * DecimalFormatSymbols object. This is the only value for which jtulach@1334: * the prefixes and suffixes are not used. jtulach@1334: * jtulach@1334: *

Infinity is formatted as a string, which typically has a single character jtulach@1334: * \u221E, with the positive or negative prefixes and suffixes jtulach@1334: * applied. The infinity string is determined by the jtulach@1334: * DecimalFormatSymbols object. jtulach@1334: * jtulach@1334: *

Negative zero ("-0") parses to jtulach@1334: *

jtulach@1334: * jtulach@1334: *

Synchronization

jtulach@1334: * jtulach@1334: *

jtulach@1334: * Decimal formats are generally not synchronized. jtulach@1334: * It is recommended to create separate format instances for each thread. jtulach@1334: * If multiple threads access a format concurrently, it must be synchronized jtulach@1334: * externally. jtulach@1334: * jtulach@1334: *

Example

jtulach@1334: * jtulach@1334: *
jtulach@1334:  * // Print out a number using the localized number, integer, currency,
jtulach@1334:  * // and percent format for each locale
jtulach@1334:  * Locale[] locales = NumberFormat.getAvailableLocales();
jtulach@1334:  * double myNumber = -1234.56;
jtulach@1334:  * NumberFormat form;
jtulach@1334:  * for (int j=0; j<4; ++j) {
jtulach@1334:  *     System.out.println("FORMAT");
jtulach@1334:  *     for (int i = 0; i < locales.length; ++i) {
jtulach@1334:  *         if (locales[i].getCountry().length() == 0) {
jtulach@1334:  *            continue; // Skip language-only locales
jtulach@1334:  *         }
jtulach@1334:  *         System.out.print(locales[i].getDisplayName());
jtulach@1334:  *         switch (j) {
jtulach@1334:  *         case 0:
jtulach@1334:  *             form = NumberFormat.getInstance(locales[i]); break;
jtulach@1334:  *         case 1:
jtulach@1334:  *             form = NumberFormat.getIntegerInstance(locales[i]); break;
jtulach@1334:  *         case 2:
jtulach@1334:  *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
jtulach@1334:  *         default:
jtulach@1334:  *             form = NumberFormat.getPercentInstance(locales[i]); break;
jtulach@1334:  *         }
jtulach@1334:  *         if (form instanceof DecimalFormat) {
jtulach@1334:  *             System.out.print(": " + ((DecimalFormat) form).toPattern());
jtulach@1334:  *         }
jtulach@1334:  *         System.out.print(" -> " + form.format(myNumber));
jtulach@1334:  *         try {
jtulach@1334:  *             System.out.println(" -> " + form.parse(form.format(myNumber)));
jtulach@1334:  *         } catch (ParseException e) {}
jtulach@1334:  *     }
jtulach@1334:  * }
jtulach@1334:  * 
jtulach@1334: * jtulach@1334: * @see Java Tutorial jtulach@1334: * @see NumberFormat jtulach@1334: * @see DecimalFormatSymbols jtulach@1334: * @see ParsePosition jtulach@1334: * @author Mark Davis jtulach@1334: * @author Alan Liu jtulach@1334: */ jtulach@1334: public class DecimalFormat extends NumberFormat { jtulach@1334: jtulach@1334: /** jtulach@1334: * Creates a DecimalFormat using the default pattern and symbols jtulach@1334: * for the default locale. This is a convenient way to obtain a jtulach@1334: * DecimalFormat when internationalization is not the main concern. jtulach@1334: *

jtulach@1334: * To obtain standard formats for a given locale, use the factory methods jtulach@1334: * on NumberFormat such as getNumberInstance. These factories will jtulach@1334: * return the most appropriate sub-class of NumberFormat for a given jtulach@1334: * locale. jtulach@1334: * jtulach@1334: * @see java.text.NumberFormat#getInstance jtulach@1334: * @see java.text.NumberFormat#getNumberInstance jtulach@1334: * @see java.text.NumberFormat#getCurrencyInstance jtulach@1334: * @see java.text.NumberFormat#getPercentInstance jtulach@1334: */ jtulach@1334: public DecimalFormat() { jtulach@1334: Locale def = Locale.getDefault(Locale.Category.FORMAT); jtulach@1334: // try to get the pattern from the cache jtulach@1334: String pattern = cachedLocaleData.get(def); jtulach@1334: if (pattern == null) { /* cache miss */ jtulach@1334: // Get the pattern for the default locale. jtulach@1334: ResourceBundle rb = LocaleData.getNumberFormatData(def); jtulach@1334: String[] all = rb.getStringArray("NumberPatterns"); jtulach@1334: pattern = all[0]; jtulach@1334: /* update cache */ jtulach@1334: cachedLocaleData.putIfAbsent(def, pattern); jtulach@1334: } jtulach@1334: jtulach@1334: // Always applyPattern after the symbols are set jtulach@1334: this.symbols = new DecimalFormatSymbols(def); jtulach@1334: applyPattern(pattern, false); jtulach@1334: } jtulach@1334: jtulach@1334: jtulach@1334: /** jtulach@1334: * Creates a DecimalFormat using the given pattern and the symbols jtulach@1334: * for the default locale. This is a convenient way to obtain a jtulach@1334: * DecimalFormat when internationalization is not the main concern. jtulach@1334: *

jtulach@1334: * To obtain standard formats for a given locale, use the factory methods jtulach@1334: * on NumberFormat such as getNumberInstance. These factories will jtulach@1334: * return the most appropriate sub-class of NumberFormat for a given jtulach@1334: * locale. jtulach@1334: * jtulach@1334: * @param pattern A non-localized pattern string. jtulach@1334: * @exception NullPointerException if pattern is null jtulach@1334: * @exception IllegalArgumentException if the given pattern is invalid. jtulach@1334: * @see java.text.NumberFormat#getInstance jtulach@1334: * @see java.text.NumberFormat#getNumberInstance jtulach@1334: * @see java.text.NumberFormat#getCurrencyInstance jtulach@1334: * @see java.text.NumberFormat#getPercentInstance jtulach@1334: */ jtulach@1334: public DecimalFormat(String pattern) { jtulach@1334: // Always applyPattern after the symbols are set jtulach@1334: this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT)); jtulach@1334: applyPattern(pattern, false); jtulach@1334: } jtulach@1334: jtulach@1334: jtulach@1334: /** jtulach@1334: * Creates a DecimalFormat using the given pattern and symbols. jtulach@1334: * Use this constructor when you need to completely customize the jtulach@1334: * behavior of the format. jtulach@1334: *

jtulach@1334: * To obtain standard formats for a given jtulach@1334: * locale, use the factory methods on NumberFormat such as jtulach@1334: * getInstance or getCurrencyInstance. If you need only minor adjustments jtulach@1334: * to a standard format, you can modify the format returned by jtulach@1334: * a NumberFormat factory method. jtulach@1334: * jtulach@1334: * @param pattern a non-localized pattern string jtulach@1334: * @param symbols the set of symbols to be used jtulach@1334: * @exception NullPointerException if any of the given arguments is null jtulach@1334: * @exception IllegalArgumentException if the given pattern is invalid jtulach@1334: * @see java.text.NumberFormat#getInstance jtulach@1334: * @see java.text.NumberFormat#getNumberInstance jtulach@1334: * @see java.text.NumberFormat#getCurrencyInstance jtulach@1334: * @see java.text.NumberFormat#getPercentInstance jtulach@1334: * @see java.text.DecimalFormatSymbols jtulach@1334: */ jtulach@1334: public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { jtulach@1334: // Always applyPattern after the symbols are set jtulach@1334: this.symbols = (DecimalFormatSymbols)symbols.clone(); jtulach@1334: applyPattern(pattern, false); jtulach@1334: } jtulach@1334: jtulach@1334: jtulach@1334: // Overrides jtulach@1334: /** jtulach@1334: * Formats a number and appends the resulting text to the given string jtulach@1334: * buffer. jtulach@1334: * The number can be of any subclass of {@link java.lang.Number}. jtulach@1334: *

jtulach@1334: * This implementation uses the maximum precision permitted. jtulach@1334: * @param number the number to format jtulach@1334: * @param toAppendTo the StringBuffer to which the formatted jtulach@1334: * text is to be appended jtulach@1334: * @param pos On input: an alignment field, if desired. jtulach@1334: * On output: the offsets of the alignment field. jtulach@1334: * @return the value passed in as toAppendTo jtulach@1334: * @exception IllegalArgumentException if number is jtulach@1334: * null or not an instance of Number. jtulach@1334: * @exception NullPointerException if toAppendTo or jtulach@1334: * pos is null jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: public final StringBuffer format(Object number, jtulach@1334: StringBuffer toAppendTo, jtulach@1334: FieldPosition pos) { jtulach@1334: if (number instanceof Long || number instanceof Integer || jtulach@1334: number instanceof Short || number instanceof Byte || jtulach@1334: number instanceof AtomicInteger || jtulach@1334: number instanceof AtomicLong || jtulach@1334: (number instanceof BigInteger && jtulach@1334: ((BigInteger)number).bitLength () < 64)) { jtulach@1334: return format(((Number)number).longValue(), toAppendTo, pos); jtulach@1334: } else if (number instanceof BigDecimal) { jtulach@1334: return format((BigDecimal)number, toAppendTo, pos); jtulach@1334: } else if (number instanceof BigInteger) { jtulach@1334: return format((BigInteger)number, toAppendTo, pos); jtulach@1334: } else if (number instanceof Number) { jtulach@1334: return format(((Number)number).doubleValue(), toAppendTo, pos); jtulach@1334: } else { jtulach@1334: throw new IllegalArgumentException("Cannot format given Object as a Number"); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Formats a double to produce a string. jtulach@1334: * @param number The double to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param fieldPosition On input: an alignment field, if desired. jtulach@1334: * On output: the offsets of the alignment field. jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @return The formatted number string jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: public StringBuffer format(double number, StringBuffer result, jtulach@1334: FieldPosition fieldPosition) { jtulach@1334: fieldPosition.setBeginIndex(0); jtulach@1334: fieldPosition.setEndIndex(0); jtulach@1334: jtulach@1334: return format(number, result, fieldPosition.getFieldDelegate()); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Formats a double to produce a string. jtulach@1334: * @param number The double to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param delegate notified of locations of sub fields jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @return The formatted number string jtulach@1334: */ jtulach@1334: private StringBuffer format(double number, StringBuffer result, jtulach@1334: FieldDelegate delegate) { jtulach@1334: if (Double.isNaN(number) || jtulach@1334: (Double.isInfinite(number) && multiplier == 0)) { jtulach@1334: int iFieldStart = result.length(); jtulach@1334: result.append(symbols.getNaN()); jtulach@1334: delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, jtulach@1334: iFieldStart, result.length(), result); jtulach@1334: return result; jtulach@1334: } jtulach@1334: jtulach@1334: /* Detecting whether a double is negative is easy with the exception of jtulach@1334: * the value -0.0. This is a double which has a zero mantissa (and jtulach@1334: * exponent), but a negative sign bit. It is semantically distinct from jtulach@1334: * a zero with a positive sign bit, and this distinction is important jtulach@1334: * to certain kinds of computations. However, it's a little tricky to jtulach@1334: * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may jtulach@1334: * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == jtulach@1334: * -Infinity. Proper detection of -0.0 is needed to deal with the jtulach@1334: * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. jtulach@1334: */ jtulach@1334: boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0); jtulach@1334: jtulach@1334: if (multiplier != 1) { jtulach@1334: number *= multiplier; jtulach@1334: } jtulach@1334: jtulach@1334: if (Double.isInfinite(number)) { jtulach@1334: if (isNegative) { jtulach@1334: append(result, negativePrefix, delegate, jtulach@1334: getNegativePrefixFieldPositions(), Field.SIGN); jtulach@1334: } else { jtulach@1334: append(result, positivePrefix, delegate, jtulach@1334: getPositivePrefixFieldPositions(), Field.SIGN); jtulach@1334: } jtulach@1334: jtulach@1334: int iFieldStart = result.length(); jtulach@1334: result.append(symbols.getInfinity()); jtulach@1334: delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, jtulach@1334: iFieldStart, result.length(), result); jtulach@1334: jtulach@1334: if (isNegative) { jtulach@1334: append(result, negativeSuffix, delegate, jtulach@1334: getNegativeSuffixFieldPositions(), Field.SIGN); jtulach@1334: } else { jtulach@1334: append(result, positiveSuffix, delegate, jtulach@1334: getPositiveSuffixFieldPositions(), Field.SIGN); jtulach@1334: } jtulach@1334: jtulach@1334: return result; jtulach@1334: } jtulach@1334: jtulach@1334: if (isNegative) { jtulach@1334: number = -number; jtulach@1334: } jtulach@1334: jtulach@1334: // at this point we are guaranteed a nonnegative finite number. jtulach@1334: assert(number >= 0 && !Double.isInfinite(number)); jtulach@1334: jtulach@1334: synchronized(digitList) { jtulach@1334: int maxIntDigits = super.getMaximumIntegerDigits(); jtulach@1334: int minIntDigits = super.getMinimumIntegerDigits(); jtulach@1334: int maxFraDigits = super.getMaximumFractionDigits(); jtulach@1334: int minFraDigits = super.getMinimumFractionDigits(); jtulach@1334: jtulach@1334: digitList.set(isNegative, number, useExponentialNotation ? jtulach@1334: maxIntDigits + maxFraDigits : maxFraDigits, jtulach@1334: !useExponentialNotation); jtulach@1334: return subformat(result, delegate, isNegative, false, jtulach@1334: maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Format a long to produce a string. jtulach@1334: * @param number The long to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param fieldPosition On input: an alignment field, if desired. jtulach@1334: * On output: the offsets of the alignment field. jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @return The formatted number string jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: public StringBuffer format(long number, StringBuffer result, jtulach@1334: FieldPosition fieldPosition) { jtulach@1334: fieldPosition.setBeginIndex(0); jtulach@1334: fieldPosition.setEndIndex(0); jtulach@1334: jtulach@1334: return format(number, result, fieldPosition.getFieldDelegate()); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Format a long to produce a string. jtulach@1334: * @param number The long to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param delegate notified of locations of sub fields jtulach@1334: * @return The formatted number string jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: private StringBuffer format(long number, StringBuffer result, jtulach@1334: FieldDelegate delegate) { jtulach@1334: boolean isNegative = (number < 0); jtulach@1334: if (isNegative) { jtulach@1334: number = -number; jtulach@1334: } jtulach@1334: jtulach@1334: // In general, long values always represent real finite numbers, so jtulach@1334: // we don't have to check for +/- Infinity or NaN. However, there jtulach@1334: // is one case we have to be careful of: The multiplier can push jtulach@1334: // a number near MIN_VALUE or MAX_VALUE outside the legal range. We jtulach@1334: // check for this before multiplying, and if it happens we use jtulach@1334: // BigInteger instead. jtulach@1334: boolean useBigInteger = false; jtulach@1334: if (number < 0) { // This can only happen if number == Long.MIN_VALUE. jtulach@1334: if (multiplier != 0) { jtulach@1334: useBigInteger = true; jtulach@1334: } jtulach@1334: } else if (multiplier != 1 && multiplier != 0) { jtulach@1334: long cutoff = Long.MAX_VALUE / multiplier; jtulach@1334: if (cutoff < 0) { jtulach@1334: cutoff = -cutoff; jtulach@1334: } jtulach@1334: useBigInteger = (number > cutoff); jtulach@1334: } jtulach@1334: jtulach@1334: if (useBigInteger) { jtulach@1334: if (isNegative) { jtulach@1334: number = -number; jtulach@1334: } jtulach@1334: BigInteger bigIntegerValue = BigInteger.valueOf(number); jtulach@1334: return format(bigIntegerValue, result, delegate, true); jtulach@1334: } jtulach@1334: jtulach@1334: number *= multiplier; jtulach@1334: if (number == 0) { jtulach@1334: isNegative = false; jtulach@1334: } else { jtulach@1334: if (multiplier < 0) { jtulach@1334: number = -number; jtulach@1334: isNegative = !isNegative; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: synchronized(digitList) { jtulach@1334: int maxIntDigits = super.getMaximumIntegerDigits(); jtulach@1334: int minIntDigits = super.getMinimumIntegerDigits(); jtulach@1334: int maxFraDigits = super.getMaximumFractionDigits(); jtulach@1334: int minFraDigits = super.getMinimumFractionDigits(); jtulach@1334: jtulach@1334: digitList.set(isNegative, number, jtulach@1334: useExponentialNotation ? maxIntDigits + maxFraDigits : 0); jtulach@1334: jtulach@1334: return subformat(result, delegate, isNegative, true, jtulach@1334: maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Formats a BigDecimal to produce a string. jtulach@1334: * @param number The BigDecimal to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param fieldPosition On input: an alignment field, if desired. jtulach@1334: * On output: the offsets of the alignment field. jtulach@1334: * @return The formatted number string jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: private StringBuffer format(BigDecimal number, StringBuffer result, jtulach@1334: FieldPosition fieldPosition) { jtulach@1334: fieldPosition.setBeginIndex(0); jtulach@1334: fieldPosition.setEndIndex(0); jtulach@1334: return format(number, result, fieldPosition.getFieldDelegate()); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Formats a BigDecimal to produce a string. jtulach@1334: * @param number The BigDecimal to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param delegate notified of locations of sub fields jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @return The formatted number string jtulach@1334: */ jtulach@1334: private StringBuffer format(BigDecimal number, StringBuffer result, jtulach@1334: FieldDelegate delegate) { jtulach@1334: if (multiplier != 1) { jtulach@1334: number = number.multiply(getBigDecimalMultiplier()); jtulach@1334: } jtulach@1334: boolean isNegative = number.signum() == -1; jtulach@1334: if (isNegative) { jtulach@1334: number = number.negate(); jtulach@1334: } jtulach@1334: jtulach@1334: synchronized(digitList) { jtulach@1334: int maxIntDigits = getMaximumIntegerDigits(); jtulach@1334: int minIntDigits = getMinimumIntegerDigits(); jtulach@1334: int maxFraDigits = getMaximumFractionDigits(); jtulach@1334: int minFraDigits = getMinimumFractionDigits(); jtulach@1334: int maximumDigits = maxIntDigits + maxFraDigits; jtulach@1334: jtulach@1334: digitList.set(isNegative, number, useExponentialNotation ? jtulach@1334: ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) : jtulach@1334: maxFraDigits, !useExponentialNotation); jtulach@1334: jtulach@1334: return subformat(result, delegate, isNegative, false, jtulach@1334: maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Format a BigInteger to produce a string. jtulach@1334: * @param number The BigInteger to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param fieldPosition On input: an alignment field, if desired. jtulach@1334: * On output: the offsets of the alignment field. jtulach@1334: * @return The formatted number string jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: private StringBuffer format(BigInteger number, StringBuffer result, jtulach@1334: FieldPosition fieldPosition) { jtulach@1334: fieldPosition.setBeginIndex(0); jtulach@1334: fieldPosition.setEndIndex(0); jtulach@1334: jtulach@1334: return format(number, result, fieldPosition.getFieldDelegate(), false); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Format a BigInteger to produce a string. jtulach@1334: * @param number The BigInteger to format jtulach@1334: * @param result where the text is to be appended jtulach@1334: * @param delegate notified of locations of sub fields jtulach@1334: * @return The formatted number string jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @see java.text.FieldPosition jtulach@1334: */ jtulach@1334: private StringBuffer format(BigInteger number, StringBuffer result, jtulach@1334: FieldDelegate delegate, boolean formatLong) { jtulach@1334: if (multiplier != 1) { jtulach@1334: number = number.multiply(getBigIntegerMultiplier()); jtulach@1334: } jtulach@1334: boolean isNegative = number.signum() == -1; jtulach@1334: if (isNegative) { jtulach@1334: number = number.negate(); jtulach@1334: } jtulach@1334: jtulach@1334: synchronized(digitList) { jtulach@1334: int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits; jtulach@1334: if (formatLong) { jtulach@1334: maxIntDigits = super.getMaximumIntegerDigits(); jtulach@1334: minIntDigits = super.getMinimumIntegerDigits(); jtulach@1334: maxFraDigits = super.getMaximumFractionDigits(); jtulach@1334: minFraDigits = super.getMinimumFractionDigits(); jtulach@1334: maximumDigits = maxIntDigits + maxFraDigits; jtulach@1334: } else { jtulach@1334: maxIntDigits = getMaximumIntegerDigits(); jtulach@1334: minIntDigits = getMinimumIntegerDigits(); jtulach@1334: maxFraDigits = getMaximumFractionDigits(); jtulach@1334: minFraDigits = getMinimumFractionDigits(); jtulach@1334: maximumDigits = maxIntDigits + maxFraDigits; jtulach@1334: if (maximumDigits < 0) { jtulach@1334: maximumDigits = Integer.MAX_VALUE; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: digitList.set(isNegative, number, jtulach@1334: useExponentialNotation ? maximumDigits : 0); jtulach@1334: jtulach@1334: return subformat(result, delegate, isNegative, true, jtulach@1334: maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Formats an Object producing an AttributedCharacterIterator. jtulach@1334: * You can use the returned AttributedCharacterIterator jtulach@1334: * to build the resulting String, as well as to determine information jtulach@1334: * about the resulting String. jtulach@1334: *

jtulach@1334: * Each attribute key of the AttributedCharacterIterator will be of type jtulach@1334: * NumberFormat.Field, with the attribute value being the jtulach@1334: * same as the attribute key. jtulach@1334: * jtulach@1334: * @exception NullPointerException if obj is null. jtulach@1334: * @exception IllegalArgumentException when the Format cannot format the jtulach@1334: * given object. jtulach@1334: * @exception ArithmeticException if rounding is needed with rounding jtulach@1334: * mode being set to RoundingMode.UNNECESSARY jtulach@1334: * @param obj The object to format jtulach@1334: * @return AttributedCharacterIterator describing the formatted value. jtulach@1334: * @since 1.4 jtulach@1334: */ jtulach@1334: public AttributedCharacterIterator formatToCharacterIterator(Object obj) { jtulach@1334: CharacterIteratorFieldDelegate delegate = jtulach@1334: new CharacterIteratorFieldDelegate(); jtulach@1334: StringBuffer sb = new StringBuffer(); jtulach@1334: jtulach@1334: if (obj instanceof Double || obj instanceof Float) { jtulach@1334: format(((Number)obj).doubleValue(), sb, delegate); jtulach@1334: } else if (obj instanceof Long || obj instanceof Integer || jtulach@1334: obj instanceof Short || obj instanceof Byte || jtulach@1334: obj instanceof AtomicInteger || obj instanceof AtomicLong) { jtulach@1334: format(((Number)obj).longValue(), sb, delegate); jtulach@1334: } else if (obj instanceof BigDecimal) { jtulach@1334: format((BigDecimal)obj, sb, delegate); jtulach@1334: } else if (obj instanceof BigInteger) { jtulach@1334: format((BigInteger)obj, sb, delegate, false); jtulach@1334: } else if (obj == null) { jtulach@1334: throw new NullPointerException( jtulach@1334: "formatToCharacterIterator must be passed non-null object"); jtulach@1334: } else { jtulach@1334: throw new IllegalArgumentException( jtulach@1334: "Cannot format given Object as a Number"); jtulach@1334: } jtulach@1334: return delegate.getIterator(sb.toString()); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Complete the formatting of a finite number. On entry, the digitList must jtulach@1334: * be filled in with the correct digits. jtulach@1334: */ jtulach@1334: private StringBuffer subformat(StringBuffer result, FieldDelegate delegate, jtulach@1334: boolean isNegative, boolean isInteger, jtulach@1334: int maxIntDigits, int minIntDigits, jtulach@1334: int maxFraDigits, int minFraDigits) { jtulach@1334: // NOTE: This isn't required anymore because DigitList takes care of this. jtulach@1334: // jtulach@1334: // // The negative of the exponent represents the number of leading jtulach@1334: // // zeros between the decimal and the first non-zero digit, for jtulach@1334: // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this jtulach@1334: // // is more than the maximum fraction digits, then we have an underflow jtulach@1334: // // for the printed representation. We recognize this here and set jtulach@1334: // // the DigitList representation to zero in this situation. jtulach@1334: // jtulach@1334: // if (-digitList.decimalAt >= getMaximumFractionDigits()) jtulach@1334: // { jtulach@1334: // digitList.count = 0; jtulach@1334: // } jtulach@1334: jtulach@1334: char zero = symbols.getZeroDigit(); jtulach@1334: int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero jtulach@1334: char grouping = symbols.getGroupingSeparator(); jtulach@1334: char decimal = isCurrencyFormat ? jtulach@1334: symbols.getMonetaryDecimalSeparator() : jtulach@1334: symbols.getDecimalSeparator(); jtulach@1334: jtulach@1334: /* Per bug 4147706, DecimalFormat must respect the sign of numbers which jtulach@1334: * format as zero. This allows sensible computations and preserves jtulach@1334: * relations such as signum(1/x) = signum(x), where x is +Infinity or jtulach@1334: * -Infinity. Prior to this fix, we always formatted zero values as if jtulach@1334: * they were positive. Liu 7/6/98. jtulach@1334: */ jtulach@1334: if (digitList.isZero()) { jtulach@1334: digitList.decimalAt = 0; // Normalize jtulach@1334: } jtulach@1334: jtulach@1334: if (isNegative) { jtulach@1334: append(result, negativePrefix, delegate, jtulach@1334: getNegativePrefixFieldPositions(), Field.SIGN); jtulach@1334: } else { jtulach@1334: append(result, positivePrefix, delegate, jtulach@1334: getPositivePrefixFieldPositions(), Field.SIGN); jtulach@1334: } jtulach@1334: jtulach@1334: if (useExponentialNotation) { jtulach@1334: int iFieldStart = result.length(); jtulach@1334: int iFieldEnd = -1; jtulach@1334: int fFieldStart = -1; jtulach@1334: jtulach@1334: // Minimum integer digits are handled in exponential format by jtulach@1334: // adjusting the exponent. For example, 0.01234 with 3 minimum jtulach@1334: // integer digits is "123.4E-4". jtulach@1334: jtulach@1334: // Maximum integer digits are interpreted as indicating the jtulach@1334: // repeating range. This is useful for engineering notation, in jtulach@1334: // which the exponent is restricted to a multiple of 3. For jtulach@1334: // example, 0.01234 with 3 maximum integer digits is "12.34e-3". jtulach@1334: // If maximum integer digits are > 1 and are larger than jtulach@1334: // minimum integer digits, then minimum integer digits are jtulach@1334: // ignored. jtulach@1334: int exponent = digitList.decimalAt; jtulach@1334: int repeat = maxIntDigits; jtulach@1334: int minimumIntegerDigits = minIntDigits; jtulach@1334: if (repeat > 1 && repeat > minIntDigits) { jtulach@1334: // A repeating range is defined; adjust to it as follows. jtulach@1334: // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; jtulach@1334: // -3,-4,-5=>-6, etc. This takes into account that the jtulach@1334: // exponent we have here is off by one from what we expect; jtulach@1334: // it is for the format 0.MMMMMx10^n. jtulach@1334: if (exponent >= 1) { jtulach@1334: exponent = ((exponent - 1) / repeat) * repeat; jtulach@1334: } else { jtulach@1334: // integer division rounds towards 0 jtulach@1334: exponent = ((exponent - repeat) / repeat) * repeat; jtulach@1334: } jtulach@1334: minimumIntegerDigits = 1; jtulach@1334: } else { jtulach@1334: // No repeating range is defined; use minimum integer digits. jtulach@1334: exponent -= minimumIntegerDigits; jtulach@1334: } jtulach@1334: jtulach@1334: // We now output a minimum number of digits, and more if there jtulach@1334: // are more digits, up to the maximum number of digits. We jtulach@1334: // place the decimal point after the "integer" digits, which jtulach@1334: // are the first (decimalAt - exponent) digits. jtulach@1334: int minimumDigits = minIntDigits + minFraDigits; jtulach@1334: if (minimumDigits < 0) { // overflow? jtulach@1334: minimumDigits = Integer.MAX_VALUE; jtulach@1334: } jtulach@1334: jtulach@1334: // The number of integer digits is handled specially if the number jtulach@1334: // is zero, since then there may be no digits. jtulach@1334: int integerDigits = digitList.isZero() ? minimumIntegerDigits : jtulach@1334: digitList.decimalAt - exponent; jtulach@1334: if (minimumDigits < integerDigits) { jtulach@1334: minimumDigits = integerDigits; jtulach@1334: } jtulach@1334: int totalDigits = digitList.count; jtulach@1334: if (minimumDigits > totalDigits) { jtulach@1334: totalDigits = minimumDigits; jtulach@1334: } jtulach@1334: boolean addedDecimalSeparator = false; jtulach@1334: jtulach@1334: for (int i=0; i 0 && count < digitList.decimalAt) { jtulach@1334: count = digitList.decimalAt; jtulach@1334: } jtulach@1334: jtulach@1334: // Handle the case where getMaximumIntegerDigits() is smaller jtulach@1334: // than the real number of integer digits. If this is so, we jtulach@1334: // output the least significant max integer digits. For example, jtulach@1334: // the value 1997 printed with 2 max integer digits is just "97". jtulach@1334: if (count > maxIntDigits) { jtulach@1334: count = maxIntDigits; jtulach@1334: digitIndex = digitList.decimalAt - count; jtulach@1334: } jtulach@1334: jtulach@1334: int sizeBeforeIntegerPart = result.length(); jtulach@1334: for (int i=count-1; i>=0; --i) { jtulach@1334: if (i < digitList.decimalAt && digitIndex < digitList.count) { jtulach@1334: // Output a real digit jtulach@1334: result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); jtulach@1334: } else { jtulach@1334: // Output a leading zero jtulach@1334: result.append(zero); jtulach@1334: } jtulach@1334: jtulach@1334: // Output grouping separator if necessary. Don't output a jtulach@1334: // grouping separator if i==0 though; that's at the end of jtulach@1334: // the integer part. jtulach@1334: if (isGroupingUsed() && i>0 && (groupingSize != 0) && jtulach@1334: (i % groupingSize == 0)) { jtulach@1334: int gStart = result.length(); jtulach@1334: result.append(grouping); jtulach@1334: delegate.formatted(Field.GROUPING_SEPARATOR, jtulach@1334: Field.GROUPING_SEPARATOR, gStart, jtulach@1334: result.length(), result); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: // Determine whether or not there are any printable fractional jtulach@1334: // digits. If we've used up the digits we know there aren't. jtulach@1334: boolean fractionPresent = (minFraDigits > 0) || jtulach@1334: (!isInteger && digitIndex < digitList.count); jtulach@1334: jtulach@1334: // If there is no fraction present, and we haven't printed any jtulach@1334: // integer digits, then print a zero. Otherwise we won't print jtulach@1334: // _any_ digits, and we won't be able to parse this string. jtulach@1334: if (!fractionPresent && result.length() == sizeBeforeIntegerPart) { jtulach@1334: result.append(zero); jtulach@1334: } jtulach@1334: jtulach@1334: delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, jtulach@1334: iFieldStart, result.length(), result); jtulach@1334: jtulach@1334: // Output the decimal separator if we always do so. jtulach@1334: int sStart = result.length(); jtulach@1334: if (decimalSeparatorAlwaysShown || fractionPresent) { jtulach@1334: result.append(decimal); jtulach@1334: } jtulach@1334: jtulach@1334: if (sStart != result.length()) { jtulach@1334: delegate.formatted(Field.DECIMAL_SEPARATOR, jtulach@1334: Field.DECIMAL_SEPARATOR, jtulach@1334: sStart, result.length(), result); jtulach@1334: } jtulach@1334: int fFieldStart = result.length(); jtulach@1334: jtulach@1334: for (int i=0; i < maxFraDigits; ++i) { jtulach@1334: // Here is where we escape from the loop. We escape if we've jtulach@1334: // output the maximum fraction digits (specified in the for jtulach@1334: // expression above). jtulach@1334: // We also stop when we've output the minimum digits and either: jtulach@1334: // we have an integer, so there is no fractional stuff to jtulach@1334: // display, or we're out of significant digits. jtulach@1334: if (i >= minFraDigits && jtulach@1334: (isInteger || digitIndex >= digitList.count)) { jtulach@1334: break; jtulach@1334: } jtulach@1334: jtulach@1334: // Output leading fractional zeros. These are zeros that come jtulach@1334: // after the decimal but before any significant digits. These jtulach@1334: // are only output if abs(number being formatted) < 1.0. jtulach@1334: if (-1-i > (digitList.decimalAt-1)) { jtulach@1334: result.append(zero); jtulach@1334: continue; jtulach@1334: } jtulach@1334: jtulach@1334: // Output a digit, if we have any precision left, or a jtulach@1334: // zero if we don't. We don't want to output noise digits. jtulach@1334: if (!isInteger && digitIndex < digitList.count) { jtulach@1334: result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); jtulach@1334: } else { jtulach@1334: result.append(zero); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: // Record field information for caller. jtulach@1334: delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, jtulach@1334: fFieldStart, result.length(), result); jtulach@1334: } jtulach@1334: jtulach@1334: if (isNegative) { jtulach@1334: append(result, negativeSuffix, delegate, jtulach@1334: getNegativeSuffixFieldPositions(), Field.SIGN); jtulach@1334: } jtulach@1334: else { jtulach@1334: append(result, positiveSuffix, delegate, jtulach@1334: getPositiveSuffixFieldPositions(), Field.SIGN); jtulach@1334: } jtulach@1334: jtulach@1334: return result; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Appends the String string to result. jtulach@1334: * delegate is notified of all the jtulach@1334: * FieldPositions in positions. jtulach@1334: *

jtulach@1334: * If one of the FieldPositions in positions jtulach@1334: * identifies a SIGN attribute, it is mapped to jtulach@1334: * signAttribute. This is used jtulach@1334: * to map the SIGN attribute to the EXPONENT jtulach@1334: * attribute as necessary. jtulach@1334: *

jtulach@1334: * This is used by subformat to add the prefix/suffix. jtulach@1334: */ jtulach@1334: private void append(StringBuffer result, String string, jtulach@1334: FieldDelegate delegate, jtulach@1334: FieldPosition[] positions, jtulach@1334: Format.Field signAttribute) { jtulach@1334: int start = result.length(); jtulach@1334: jtulach@1334: if (string.length() > 0) { jtulach@1334: result.append(string); jtulach@1334: for (int counter = 0, max = positions.length; counter < max; jtulach@1334: counter++) { jtulach@1334: FieldPosition fp = positions[counter]; jtulach@1334: Format.Field attribute = fp.getFieldAttribute(); jtulach@1334: jtulach@1334: if (attribute == Field.SIGN) { jtulach@1334: attribute = signAttribute; jtulach@1334: } jtulach@1334: delegate.formatted(attribute, attribute, jtulach@1334: start + fp.getBeginIndex(), jtulach@1334: start + fp.getEndIndex(), result); jtulach@1334: } jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Parses text from a string to produce a Number. jtulach@1334: *

jtulach@1334: * The method attempts to parse text starting at the index given by jtulach@1334: * pos. jtulach@1334: * If parsing succeeds, then the index of pos is updated jtulach@1334: * to the index after the last character used (parsing does not necessarily jtulach@1334: * use all characters up to the end of the string), and the parsed jtulach@1334: * number is returned. The updated pos can be used to jtulach@1334: * indicate the starting point for the next call to this method. jtulach@1334: * If an error occurs, then the index of pos is not jtulach@1334: * changed, the error index of pos is set to the index of jtulach@1334: * the character where the error occurred, and null is returned. jtulach@1334: *

jtulach@1334: * The subclass returned depends on the value of {@link #isParseBigDecimal} jtulach@1334: * as well as on the string being parsed. jtulach@1334: *

jtulach@1334: *

jtulach@1334: * DecimalFormat parses all Unicode characters that represent jtulach@1334: * decimal digits, as defined by Character.digit(). In jtulach@1334: * addition, DecimalFormat also recognizes as digits the ten jtulach@1334: * consecutive characters starting with the localized zero digit defined in jtulach@1334: * the DecimalFormatSymbols object. jtulach@1334: * jtulach@1334: * @param text the string to be parsed jtulach@1334: * @param pos A ParsePosition object with index and error jtulach@1334: * index information as described above. jtulach@1334: * @return the parsed value, or null if the parse fails jtulach@1334: * @exception NullPointerException if text or jtulach@1334: * pos is null. jtulach@1334: */ jtulach@1334: public Number parse(String text, ParsePosition pos) { jtulach@1334: // special case NaN jtulach@1334: if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { jtulach@1334: pos.index = pos.index + symbols.getNaN().length(); jtulach@1334: return new Double(Double.NaN); jtulach@1334: } jtulach@1334: jtulach@1334: boolean[] status = new boolean[STATUS_LENGTH]; jtulach@1334: if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) { jtulach@1334: return null; jtulach@1334: } jtulach@1334: jtulach@1334: // special case INFINITY jtulach@1334: if (status[STATUS_INFINITE]) { jtulach@1334: if (status[STATUS_POSITIVE] == (multiplier >= 0)) { jtulach@1334: return new Double(Double.POSITIVE_INFINITY); jtulach@1334: } else { jtulach@1334: return new Double(Double.NEGATIVE_INFINITY); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (multiplier == 0) { jtulach@1334: if (digitList.isZero()) { jtulach@1334: return new Double(Double.NaN); jtulach@1334: } else if (status[STATUS_POSITIVE]) { jtulach@1334: return new Double(Double.POSITIVE_INFINITY); jtulach@1334: } else { jtulach@1334: return new Double(Double.NEGATIVE_INFINITY); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (isParseBigDecimal()) { jtulach@1334: BigDecimal bigDecimalResult = digitList.getBigDecimal(); jtulach@1334: jtulach@1334: if (multiplier != 1) { jtulach@1334: try { jtulach@1334: bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier()); jtulach@1334: } jtulach@1334: catch (ArithmeticException e) { // non-terminating decimal expansion jtulach@1334: bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (!status[STATUS_POSITIVE]) { jtulach@1334: bigDecimalResult = bigDecimalResult.negate(); jtulach@1334: } jtulach@1334: return bigDecimalResult; jtulach@1334: } else { jtulach@1334: boolean gotDouble = true; jtulach@1334: boolean gotLongMinimum = false; jtulach@1334: double doubleResult = 0.0; jtulach@1334: long longResult = 0; jtulach@1334: jtulach@1334: // Finally, have DigitList parse the digits into a value. jtulach@1334: if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) { jtulach@1334: gotDouble = false; jtulach@1334: longResult = digitList.getLong(); jtulach@1334: if (longResult < 0) { // got Long.MIN_VALUE jtulach@1334: gotLongMinimum = true; jtulach@1334: } jtulach@1334: } else { jtulach@1334: doubleResult = digitList.getDouble(); jtulach@1334: } jtulach@1334: jtulach@1334: // Divide by multiplier. We have to be careful here not to do jtulach@1334: // unneeded conversions between double and long. jtulach@1334: if (multiplier != 1) { jtulach@1334: if (gotDouble) { jtulach@1334: doubleResult /= multiplier; jtulach@1334: } else { jtulach@1334: // Avoid converting to double if we can jtulach@1334: if (longResult % multiplier == 0) { jtulach@1334: longResult /= multiplier; jtulach@1334: } else { jtulach@1334: doubleResult = ((double)longResult) / multiplier; jtulach@1334: gotDouble = true; jtulach@1334: } jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (!status[STATUS_POSITIVE] && !gotLongMinimum) { jtulach@1334: doubleResult = -doubleResult; jtulach@1334: longResult = -longResult; jtulach@1334: } jtulach@1334: jtulach@1334: // At this point, if we divided the result by the multiplier, the jtulach@1334: // result may fit into a long. We check for this case and return jtulach@1334: // a long if possible. jtulach@1334: // We must do this AFTER applying the negative (if appropriate) jtulach@1334: // in order to handle the case of LONG_MIN; otherwise, if we do jtulach@1334: // this with a positive value -LONG_MIN, the double is > 0, but jtulach@1334: // the long is < 0. We also must retain a double in the case of jtulach@1334: // -0.0, which will compare as == to a long 0 cast to a double jtulach@1334: // (bug 4162852). jtulach@1334: if (multiplier != 1 && gotDouble) { jtulach@1334: longResult = (long)doubleResult; jtulach@1334: gotDouble = ((doubleResult != (double)longResult) || jtulach@1334: (doubleResult == 0.0 && 1/doubleResult < 0.0)) && jtulach@1334: !isParseIntegerOnly(); jtulach@1334: } jtulach@1334: jtulach@1334: return gotDouble ? jtulach@1334: (Number)new Double(doubleResult) : (Number)new Long(longResult); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Return a BigInteger multiplier. jtulach@1334: */ jtulach@1334: private BigInteger getBigIntegerMultiplier() { jtulach@1334: if (bigIntegerMultiplier == null) { jtulach@1334: bigIntegerMultiplier = BigInteger.valueOf(multiplier); jtulach@1334: } jtulach@1334: return bigIntegerMultiplier; jtulach@1334: } jtulach@1334: private transient BigInteger bigIntegerMultiplier; jtulach@1334: jtulach@1334: /** jtulach@1334: * Return a BigDecimal multiplier. jtulach@1334: */ jtulach@1334: private BigDecimal getBigDecimalMultiplier() { jtulach@1334: if (bigDecimalMultiplier == null) { jtulach@1334: bigDecimalMultiplier = new BigDecimal(multiplier); jtulach@1334: } jtulach@1334: return bigDecimalMultiplier; jtulach@1334: } jtulach@1334: private transient BigDecimal bigDecimalMultiplier; jtulach@1334: jtulach@1334: private static final int STATUS_INFINITE = 0; jtulach@1334: private static final int STATUS_POSITIVE = 1; jtulach@1334: private static final int STATUS_LENGTH = 2; jtulach@1334: jtulach@1334: /** jtulach@1334: * Parse the given text into a number. The text is parsed beginning at jtulach@1334: * parsePosition, until an unparseable character is seen. jtulach@1334: * @param text The string to parse. jtulach@1334: * @param parsePosition The position at which to being parsing. Upon jtulach@1334: * return, the first unparseable character. jtulach@1334: * @param digits The DigitList to set to the parsed value. jtulach@1334: * @param isExponent If true, parse an exponent. This means no jtulach@1334: * infinite values and integer only. jtulach@1334: * @param status Upon return contains boolean status flags indicating jtulach@1334: * whether the value was infinite and whether it was positive. jtulach@1334: */ jtulach@1334: private final boolean subparse(String text, ParsePosition parsePosition, jtulach@1334: String positivePrefix, String negativePrefix, jtulach@1334: DigitList digits, boolean isExponent, jtulach@1334: boolean status[]) { jtulach@1334: int position = parsePosition.index; jtulach@1334: int oldStart = parsePosition.index; jtulach@1334: int backup; jtulach@1334: boolean gotPositive, gotNegative; jtulach@1334: jtulach@1334: // check for positivePrefix; take longest jtulach@1334: gotPositive = text.regionMatches(position, positivePrefix, 0, jtulach@1334: positivePrefix.length()); jtulach@1334: gotNegative = text.regionMatches(position, negativePrefix, 0, jtulach@1334: negativePrefix.length()); jtulach@1334: jtulach@1334: if (gotPositive && gotNegative) { jtulach@1334: if (positivePrefix.length() > negativePrefix.length()) { jtulach@1334: gotNegative = false; jtulach@1334: } else if (positivePrefix.length() < negativePrefix.length()) { jtulach@1334: gotPositive = false; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (gotPositive) { jtulach@1334: position += positivePrefix.length(); jtulach@1334: } else if (gotNegative) { jtulach@1334: position += negativePrefix.length(); jtulach@1334: } else { jtulach@1334: parsePosition.errorIndex = position; jtulach@1334: return false; jtulach@1334: } jtulach@1334: jtulach@1334: // process digits or Inf, find decimal position jtulach@1334: status[STATUS_INFINITE] = false; jtulach@1334: if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0, jtulach@1334: symbols.getInfinity().length())) { jtulach@1334: position += symbols.getInfinity().length(); jtulach@1334: status[STATUS_INFINITE] = true; jtulach@1334: } else { jtulach@1334: // We now have a string of digits, possibly with grouping symbols, jtulach@1334: // and decimal points. We want to process these into a DigitList. jtulach@1334: // We don't want to put a bunch of leading zeros into the DigitList jtulach@1334: // though, so we keep track of the location of the decimal point, jtulach@1334: // put only significant digits into the DigitList, and adjust the jtulach@1334: // exponent as needed. jtulach@1334: jtulach@1334: digits.decimalAt = digits.count = 0; jtulach@1334: char zero = symbols.getZeroDigit(); jtulach@1334: char decimal = isCurrencyFormat ? jtulach@1334: symbols.getMonetaryDecimalSeparator() : jtulach@1334: symbols.getDecimalSeparator(); jtulach@1334: char grouping = symbols.getGroupingSeparator(); jtulach@1334: String exponentString = symbols.getExponentSeparator(); jtulach@1334: boolean sawDecimal = false; jtulach@1334: boolean sawExponent = false; jtulach@1334: boolean sawDigit = false; jtulach@1334: int exponent = 0; // Set to the exponent value, if any jtulach@1334: jtulach@1334: // We have to track digitCount ourselves, because digits.count will jtulach@1334: // pin when the maximum allowable digits is reached. jtulach@1334: int digitCount = 0; jtulach@1334: jtulach@1334: backup = -1; jtulach@1334: for (; position < text.length(); ++position) { jtulach@1334: char ch = text.charAt(position); jtulach@1334: jtulach@1334: /* We recognize all digit ranges, not only the Latin digit range jtulach@1334: * '0'..'9'. We do so by using the Character.digit() method, jtulach@1334: * which converts a valid Unicode digit to the range 0..9. jtulach@1334: * jtulach@1334: * The character 'ch' may be a digit. If so, place its value jtulach@1334: * from 0 to 9 in 'digit'. First try using the locale digit, jtulach@1334: * which may or MAY NOT be a standard Unicode digit range. If jtulach@1334: * this fails, try using the standard Unicode digit ranges by jtulach@1334: * calling Character.digit(). If this also fails, digit will jtulach@1334: * have a value outside the range 0..9. jtulach@1334: */ jtulach@1334: int digit = ch - zero; jtulach@1334: if (digit < 0 || digit > 9) { jtulach@1334: digit = Character.digit(ch, 10); jtulach@1334: } jtulach@1334: jtulach@1334: if (digit == 0) { jtulach@1334: // Cancel out backup setting (see grouping handler below) jtulach@1334: backup = -1; // Do this BEFORE continue statement below!!! jtulach@1334: sawDigit = true; jtulach@1334: jtulach@1334: // Handle leading zeros jtulach@1334: if (digits.count == 0) { jtulach@1334: // Ignore leading zeros in integer part of number. jtulach@1334: if (!sawDecimal) { jtulach@1334: continue; jtulach@1334: } jtulach@1334: jtulach@1334: // If we have seen the decimal, but no significant jtulach@1334: // digits yet, then we account for leading zeros by jtulach@1334: // decrementing the digits.decimalAt into negative jtulach@1334: // values. jtulach@1334: --digits.decimalAt; jtulach@1334: } else { jtulach@1334: ++digitCount; jtulach@1334: digits.append((char)(digit + '0')); jtulach@1334: } jtulach@1334: } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above jtulach@1334: sawDigit = true; jtulach@1334: ++digitCount; jtulach@1334: digits.append((char)(digit + '0')); jtulach@1334: jtulach@1334: // Cancel out backup setting (see grouping handler below) jtulach@1334: backup = -1; jtulach@1334: } else if (!isExponent && ch == decimal) { jtulach@1334: // If we're only parsing integers, or if we ALREADY saw the jtulach@1334: // decimal, then don't parse this one. jtulach@1334: if (isParseIntegerOnly() || sawDecimal) { jtulach@1334: break; jtulach@1334: } jtulach@1334: digits.decimalAt = digitCount; // Not digits.count! jtulach@1334: sawDecimal = true; jtulach@1334: } else if (!isExponent && ch == grouping && isGroupingUsed()) { jtulach@1334: if (sawDecimal) { jtulach@1334: break; jtulach@1334: } jtulach@1334: // Ignore grouping characters, if we are using them, but jtulach@1334: // require that they be followed by a digit. Otherwise jtulach@1334: // we backup and reprocess them. jtulach@1334: backup = position; jtulach@1334: } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length()) jtulach@1334: && !sawExponent) { jtulach@1334: // Process the exponent by recursively calling this method. jtulach@1334: ParsePosition pos = new ParsePosition(position + exponentString.length()); jtulach@1334: boolean[] stat = new boolean[STATUS_LENGTH]; jtulach@1334: DigitList exponentDigits = new DigitList(); jtulach@1334: jtulach@1334: if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) && jtulach@1334: exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) { jtulach@1334: position = pos.index; // Advance past the exponent jtulach@1334: exponent = (int)exponentDigits.getLong(); jtulach@1334: if (!stat[STATUS_POSITIVE]) { jtulach@1334: exponent = -exponent; jtulach@1334: } jtulach@1334: sawExponent = true; jtulach@1334: } jtulach@1334: break; // Whether we fail or succeed, we exit this loop jtulach@1334: } jtulach@1334: else { jtulach@1334: break; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (backup != -1) { jtulach@1334: position = backup; jtulach@1334: } jtulach@1334: jtulach@1334: // If there was no decimal point we have an integer jtulach@1334: if (!sawDecimal) { jtulach@1334: digits.decimalAt = digitCount; // Not digits.count! jtulach@1334: } jtulach@1334: jtulach@1334: // Adjust for exponent, if any jtulach@1334: digits.decimalAt += exponent; jtulach@1334: jtulach@1334: // If none of the text string was recognized. For example, parse jtulach@1334: // "x" with pattern "#0.00" (return index and error index both 0) jtulach@1334: // parse "$" with pattern "$#0.00". (return index 0 and error jtulach@1334: // index 1). jtulach@1334: if (!sawDigit && digitCount == 0) { jtulach@1334: parsePosition.index = oldStart; jtulach@1334: parsePosition.errorIndex = oldStart; jtulach@1334: return false; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: // check for suffix jtulach@1334: if (!isExponent) { jtulach@1334: if (gotPositive) { jtulach@1334: gotPositive = text.regionMatches(position,positiveSuffix,0, jtulach@1334: positiveSuffix.length()); jtulach@1334: } jtulach@1334: if (gotNegative) { jtulach@1334: gotNegative = text.regionMatches(position,negativeSuffix,0, jtulach@1334: negativeSuffix.length()); jtulach@1334: } jtulach@1334: jtulach@1334: // if both match, take longest jtulach@1334: if (gotPositive && gotNegative) { jtulach@1334: if (positiveSuffix.length() > negativeSuffix.length()) { jtulach@1334: gotNegative = false; jtulach@1334: } else if (positiveSuffix.length() < negativeSuffix.length()) { jtulach@1334: gotPositive = false; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: // fail if neither or both jtulach@1334: if (gotPositive == gotNegative) { jtulach@1334: parsePosition.errorIndex = position; jtulach@1334: return false; jtulach@1334: } jtulach@1334: jtulach@1334: parsePosition.index = position + jtulach@1334: (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success! jtulach@1334: } else { jtulach@1334: parsePosition.index = position; jtulach@1334: } jtulach@1334: jtulach@1334: status[STATUS_POSITIVE] = gotPositive; jtulach@1334: if (parsePosition.index == oldStart) { jtulach@1334: parsePosition.errorIndex = position; jtulach@1334: return false; jtulach@1334: } jtulach@1334: return true; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns a copy of the decimal format symbols, which is generally not jtulach@1334: * changed by the programmer or user. jtulach@1334: * @return a copy of the desired DecimalFormatSymbols jtulach@1334: * @see java.text.DecimalFormatSymbols jtulach@1334: */ jtulach@1334: public DecimalFormatSymbols getDecimalFormatSymbols() { jtulach@1334: try { jtulach@1334: // don't allow multiple references jtulach@1334: return (DecimalFormatSymbols) symbols.clone(); jtulach@1334: } catch (Exception foo) { jtulach@1334: return null; // should never happen jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the decimal format symbols, which is generally not changed jtulach@1334: * by the programmer or user. jtulach@1334: * @param newSymbols desired DecimalFormatSymbols jtulach@1334: * @see java.text.DecimalFormatSymbols jtulach@1334: */ jtulach@1334: public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { jtulach@1334: try { jtulach@1334: // don't allow multiple references jtulach@1334: symbols = (DecimalFormatSymbols) newSymbols.clone(); jtulach@1334: expandAffixes(); jtulach@1334: } catch (Exception foo) { jtulach@1334: // should never happen jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Get the positive prefix. jtulach@1334: *

Examples: +123, $123, sFr123 jtulach@1334: */ jtulach@1334: public String getPositivePrefix () { jtulach@1334: return positivePrefix; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Set the positive prefix. jtulach@1334: *

Examples: +123, $123, sFr123 jtulach@1334: */ jtulach@1334: public void setPositivePrefix (String newValue) { jtulach@1334: positivePrefix = newValue; jtulach@1334: posPrefixPattern = null; jtulach@1334: positivePrefixFieldPositions = null; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns the FieldPositions of the fields in the prefix used for jtulach@1334: * positive numbers. This is not used if the user has explicitly set jtulach@1334: * a positive prefix via setPositivePrefix. This is jtulach@1334: * lazily created. jtulach@1334: * jtulach@1334: * @return FieldPositions in positive prefix jtulach@1334: */ jtulach@1334: private FieldPosition[] getPositivePrefixFieldPositions() { jtulach@1334: if (positivePrefixFieldPositions == null) { jtulach@1334: if (posPrefixPattern != null) { jtulach@1334: positivePrefixFieldPositions = expandAffix(posPrefixPattern); jtulach@1334: } jtulach@1334: else { jtulach@1334: positivePrefixFieldPositions = EmptyFieldPositionArray; jtulach@1334: } jtulach@1334: } jtulach@1334: return positivePrefixFieldPositions; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Get the negative prefix. jtulach@1334: *

Examples: -123, ($123) (with negative suffix), sFr-123 jtulach@1334: */ jtulach@1334: public String getNegativePrefix () { jtulach@1334: return negativePrefix; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Set the negative prefix. jtulach@1334: *

Examples: -123, ($123) (with negative suffix), sFr-123 jtulach@1334: */ jtulach@1334: public void setNegativePrefix (String newValue) { jtulach@1334: negativePrefix = newValue; jtulach@1334: negPrefixPattern = null; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns the FieldPositions of the fields in the prefix used for jtulach@1334: * negative numbers. This is not used if the user has explicitly set jtulach@1334: * a negative prefix via setNegativePrefix. This is jtulach@1334: * lazily created. jtulach@1334: * jtulach@1334: * @return FieldPositions in positive prefix jtulach@1334: */ jtulach@1334: private FieldPosition[] getNegativePrefixFieldPositions() { jtulach@1334: if (negativePrefixFieldPositions == null) { jtulach@1334: if (negPrefixPattern != null) { jtulach@1334: negativePrefixFieldPositions = expandAffix(negPrefixPattern); jtulach@1334: } jtulach@1334: else { jtulach@1334: negativePrefixFieldPositions = EmptyFieldPositionArray; jtulach@1334: } jtulach@1334: } jtulach@1334: return negativePrefixFieldPositions; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Get the positive suffix. jtulach@1334: *

Example: 123% jtulach@1334: */ jtulach@1334: public String getPositiveSuffix () { jtulach@1334: return positiveSuffix; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Set the positive suffix. jtulach@1334: *

Example: 123% jtulach@1334: */ jtulach@1334: public void setPositiveSuffix (String newValue) { jtulach@1334: positiveSuffix = newValue; jtulach@1334: posSuffixPattern = null; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns the FieldPositions of the fields in the suffix used for jtulach@1334: * positive numbers. This is not used if the user has explicitly set jtulach@1334: * a positive suffix via setPositiveSuffix. This is jtulach@1334: * lazily created. jtulach@1334: * jtulach@1334: * @return FieldPositions in positive prefix jtulach@1334: */ jtulach@1334: private FieldPosition[] getPositiveSuffixFieldPositions() { jtulach@1334: if (positiveSuffixFieldPositions == null) { jtulach@1334: if (posSuffixPattern != null) { jtulach@1334: positiveSuffixFieldPositions = expandAffix(posSuffixPattern); jtulach@1334: } jtulach@1334: else { jtulach@1334: positiveSuffixFieldPositions = EmptyFieldPositionArray; jtulach@1334: } jtulach@1334: } jtulach@1334: return positiveSuffixFieldPositions; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Get the negative suffix. jtulach@1334: *

Examples: -123%, ($123) (with positive suffixes) jtulach@1334: */ jtulach@1334: public String getNegativeSuffix () { jtulach@1334: return negativeSuffix; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Set the negative suffix. jtulach@1334: *

Examples: 123% jtulach@1334: */ jtulach@1334: public void setNegativeSuffix (String newValue) { jtulach@1334: negativeSuffix = newValue; jtulach@1334: negSuffixPattern = null; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns the FieldPositions of the fields in the suffix used for jtulach@1334: * negative numbers. This is not used if the user has explicitly set jtulach@1334: * a negative suffix via setNegativeSuffix. This is jtulach@1334: * lazily created. jtulach@1334: * jtulach@1334: * @return FieldPositions in positive prefix jtulach@1334: */ jtulach@1334: private FieldPosition[] getNegativeSuffixFieldPositions() { jtulach@1334: if (negativeSuffixFieldPositions == null) { jtulach@1334: if (negSuffixPattern != null) { jtulach@1334: negativeSuffixFieldPositions = expandAffix(negSuffixPattern); jtulach@1334: } jtulach@1334: else { jtulach@1334: negativeSuffixFieldPositions = EmptyFieldPositionArray; jtulach@1334: } jtulach@1334: } jtulach@1334: return negativeSuffixFieldPositions; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the multiplier for use in percent, per mille, and similar jtulach@1334: * formats. jtulach@1334: * jtulach@1334: * @see #setMultiplier(int) jtulach@1334: */ jtulach@1334: public int getMultiplier () { jtulach@1334: return multiplier; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the multiplier for use in percent, per mille, and similar jtulach@1334: * formats. jtulach@1334: * For a percent format, set the multiplier to 100 and the suffixes to jtulach@1334: * have '%' (for Arabic, use the Arabic percent sign). jtulach@1334: * For a per mille format, set the multiplier to 1000 and the suffixes to jtulach@1334: * have '\u2030'. jtulach@1334: * jtulach@1334: *

Example: with multiplier 100, 1.23 is formatted as "123", and jtulach@1334: * "123" is parsed into 1.23. jtulach@1334: * jtulach@1334: * @see #getMultiplier jtulach@1334: */ jtulach@1334: public void setMultiplier (int newValue) { jtulach@1334: multiplier = newValue; jtulach@1334: bigDecimalMultiplier = null; jtulach@1334: bigIntegerMultiplier = null; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Return the grouping size. Grouping size is the number of digits between jtulach@1334: * grouping separators in the integer portion of a number. For example, jtulach@1334: * in the number "123,456.78", the grouping size is 3. jtulach@1334: * @see #setGroupingSize jtulach@1334: * @see java.text.NumberFormat#isGroupingUsed jtulach@1334: * @see java.text.DecimalFormatSymbols#getGroupingSeparator jtulach@1334: */ jtulach@1334: public int getGroupingSize () { jtulach@1334: return groupingSize; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Set the grouping size. Grouping size is the number of digits between jtulach@1334: * grouping separators in the integer portion of a number. For example, jtulach@1334: * in the number "123,456.78", the grouping size is 3. jtulach@1334: *
jtulach@1334: * The value passed in is converted to a byte, which may lose information. jtulach@1334: * @see #getGroupingSize jtulach@1334: * @see java.text.NumberFormat#setGroupingUsed jtulach@1334: * @see java.text.DecimalFormatSymbols#setGroupingSeparator jtulach@1334: */ jtulach@1334: public void setGroupingSize (int newValue) { jtulach@1334: groupingSize = (byte)newValue; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Allows you to get the behavior of the decimal separator with integers. jtulach@1334: * (The decimal separator will always appear with decimals.) jtulach@1334: *

Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345 jtulach@1334: */ jtulach@1334: public boolean isDecimalSeparatorAlwaysShown() { jtulach@1334: return decimalSeparatorAlwaysShown; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Allows you to set the behavior of the decimal separator with integers. jtulach@1334: * (The decimal separator will always appear with decimals.) jtulach@1334: *

Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345 jtulach@1334: */ jtulach@1334: public void setDecimalSeparatorAlwaysShown(boolean newValue) { jtulach@1334: decimalSeparatorAlwaysShown = newValue; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)} jtulach@1334: * method returns BigDecimal. The default value is false. jtulach@1334: * @see #setParseBigDecimal jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: public boolean isParseBigDecimal() { jtulach@1334: return parseBigDecimal; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)} jtulach@1334: * method returns BigDecimal. jtulach@1334: * @see #isParseBigDecimal jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: public void setParseBigDecimal(boolean newValue) { jtulach@1334: parseBigDecimal = newValue; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Standard override; no change in semantics. jtulach@1334: */ jtulach@1334: public Object clone() { jtulach@1334: try { jtulach@1334: DecimalFormat other = (DecimalFormat) super.clone(); jtulach@1334: other.symbols = (DecimalFormatSymbols) symbols.clone(); jtulach@1334: other.digitList = (DigitList) digitList.clone(); jtulach@1334: return other; jtulach@1334: } catch (Exception e) { jtulach@1334: throw new InternalError(); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Overrides equals jtulach@1334: */ jtulach@1334: public boolean equals(Object obj) jtulach@1334: { jtulach@1334: if (obj == null) return false; jtulach@1334: if (!super.equals(obj)) return false; // super does class check jtulach@1334: DecimalFormat other = (DecimalFormat) obj; jtulach@1334: return ((posPrefixPattern == other.posPrefixPattern && jtulach@1334: positivePrefix.equals(other.positivePrefix)) jtulach@1334: || (posPrefixPattern != null && jtulach@1334: posPrefixPattern.equals(other.posPrefixPattern))) jtulach@1334: && ((posSuffixPattern == other.posSuffixPattern && jtulach@1334: positiveSuffix.equals(other.positiveSuffix)) jtulach@1334: || (posSuffixPattern != null && jtulach@1334: posSuffixPattern.equals(other.posSuffixPattern))) jtulach@1334: && ((negPrefixPattern == other.negPrefixPattern && jtulach@1334: negativePrefix.equals(other.negativePrefix)) jtulach@1334: || (negPrefixPattern != null && jtulach@1334: negPrefixPattern.equals(other.negPrefixPattern))) jtulach@1334: && ((negSuffixPattern == other.negSuffixPattern && jtulach@1334: negativeSuffix.equals(other.negativeSuffix)) jtulach@1334: || (negSuffixPattern != null && jtulach@1334: negSuffixPattern.equals(other.negSuffixPattern))) jtulach@1334: && multiplier == other.multiplier jtulach@1334: && groupingSize == other.groupingSize jtulach@1334: && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown jtulach@1334: && parseBigDecimal == other.parseBigDecimal jtulach@1334: && useExponentialNotation == other.useExponentialNotation jtulach@1334: && (!useExponentialNotation || jtulach@1334: minExponentDigits == other.minExponentDigits) jtulach@1334: && maximumIntegerDigits == other.maximumIntegerDigits jtulach@1334: && minimumIntegerDigits == other.minimumIntegerDigits jtulach@1334: && maximumFractionDigits == other.maximumFractionDigits jtulach@1334: && minimumFractionDigits == other.minimumFractionDigits jtulach@1334: && roundingMode == other.roundingMode jtulach@1334: && symbols.equals(other.symbols); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Overrides hashCode jtulach@1334: */ jtulach@1334: public int hashCode() { jtulach@1334: return super.hashCode() * 37 + positivePrefix.hashCode(); jtulach@1334: // just enough fields for a reasonable distribution jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Synthesizes a pattern string that represents the current state jtulach@1334: * of this Format object. jtulach@1334: * @see #applyPattern jtulach@1334: */ jtulach@1334: public String toPattern() { jtulach@1334: return toPattern( false ); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Synthesizes a localized pattern string that represents the current jtulach@1334: * state of this Format object. jtulach@1334: * @see #applyPattern jtulach@1334: */ jtulach@1334: public String toLocalizedPattern() { jtulach@1334: return toPattern( true ); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Expand the affix pattern strings into the expanded affix strings. If any jtulach@1334: * affix pattern string is null, do not expand it. This method should be jtulach@1334: * called any time the symbols or the affix patterns change in order to keep jtulach@1334: * the expanded affix strings up to date. jtulach@1334: */ jtulach@1334: private void expandAffixes() { jtulach@1334: // Reuse one StringBuffer for better performance jtulach@1334: StringBuffer buffer = new StringBuffer(); jtulach@1334: if (posPrefixPattern != null) { jtulach@1334: positivePrefix = expandAffix(posPrefixPattern, buffer); jtulach@1334: positivePrefixFieldPositions = null; jtulach@1334: } jtulach@1334: if (posSuffixPattern != null) { jtulach@1334: positiveSuffix = expandAffix(posSuffixPattern, buffer); jtulach@1334: positiveSuffixFieldPositions = null; jtulach@1334: } jtulach@1334: if (negPrefixPattern != null) { jtulach@1334: negativePrefix = expandAffix(negPrefixPattern, buffer); jtulach@1334: negativePrefixFieldPositions = null; jtulach@1334: } jtulach@1334: if (negSuffixPattern != null) { jtulach@1334: negativeSuffix = expandAffix(negSuffixPattern, buffer); jtulach@1334: negativeSuffixFieldPositions = null; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Expand an affix pattern into an affix string. All characters in the jtulach@1334: * pattern are literal unless prefixed by QUOTE. The following characters jtulach@1334: * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, jtulach@1334: * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + jtulach@1334: * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 jtulach@1334: * currency code. Any other character after a QUOTE represents itself. jtulach@1334: * QUOTE must be followed by another character; QUOTE may not occur by jtulach@1334: * itself at the end of the pattern. jtulach@1334: * jtulach@1334: * @param pattern the non-null, possibly empty pattern jtulach@1334: * @param buffer a scratch StringBuffer; its contents will be lost jtulach@1334: * @return the expanded equivalent of pattern jtulach@1334: */ jtulach@1334: private String expandAffix(String pattern, StringBuffer buffer) { jtulach@1334: buffer.setLength(0); jtulach@1334: for (int i=0; i 0) { jtulach@1334: if (positions == null) { jtulach@1334: positions = new ArrayList(2); jtulach@1334: } jtulach@1334: FieldPosition fp = new FieldPosition(Field.CURRENCY); jtulach@1334: fp.setBeginIndex(stringIndex); jtulach@1334: fp.setEndIndex(stringIndex + string.length()); jtulach@1334: positions.add(fp); jtulach@1334: stringIndex += string.length(); jtulach@1334: } jtulach@1334: continue; jtulach@1334: case PATTERN_PERCENT: jtulach@1334: c = symbols.getPercent(); jtulach@1334: field = -1; jtulach@1334: fieldID = Field.PERCENT; jtulach@1334: break; jtulach@1334: case PATTERN_PER_MILLE: jtulach@1334: c = symbols.getPerMill(); jtulach@1334: field = -1; jtulach@1334: fieldID = Field.PERMILLE; jtulach@1334: break; jtulach@1334: case PATTERN_MINUS: jtulach@1334: c = symbols.getMinusSign(); jtulach@1334: field = -1; jtulach@1334: fieldID = Field.SIGN; jtulach@1334: break; jtulach@1334: } jtulach@1334: if (fieldID != null) { jtulach@1334: if (positions == null) { jtulach@1334: positions = new ArrayList(2); jtulach@1334: } jtulach@1334: FieldPosition fp = new FieldPosition(fieldID, field); jtulach@1334: fp.setBeginIndex(stringIndex); jtulach@1334: fp.setEndIndex(stringIndex + 1); jtulach@1334: positions.add(fp); jtulach@1334: } jtulach@1334: } jtulach@1334: stringIndex++; jtulach@1334: } jtulach@1334: if (positions != null) { jtulach@1334: return (FieldPosition[])positions.toArray(EmptyFieldPositionArray); jtulach@1334: } jtulach@1334: return EmptyFieldPositionArray; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Appends an affix pattern to the given StringBuffer, quoting special jtulach@1334: * characters as needed. Uses the internal affix pattern, if that exists, jtulach@1334: * or the literal affix, if the internal affix pattern is null. The jtulach@1334: * appended string will generate the same affix pattern (or literal affix) jtulach@1334: * when passed to toPattern(). jtulach@1334: * jtulach@1334: * @param buffer the affix string is appended to this jtulach@1334: * @param affixPattern a pattern such as posPrefixPattern; may be null jtulach@1334: * @param expAffix a corresponding expanded affix, such as positivePrefix. jtulach@1334: * Ignored unless affixPattern is null. If affixPattern is null, then jtulach@1334: * expAffix is appended as a literal affix. jtulach@1334: * @param localized true if the appended pattern should contain localized jtulach@1334: * pattern characters; otherwise, non-localized pattern chars are appended jtulach@1334: */ jtulach@1334: private void appendAffix(StringBuffer buffer, String affixPattern, jtulach@1334: String expAffix, boolean localized) { jtulach@1334: if (affixPattern == null) { jtulach@1334: appendAffix(buffer, expAffix, localized); jtulach@1334: } else { jtulach@1334: int i; jtulach@1334: for (int pos=0; pos pos) { jtulach@1334: appendAffix(buffer, affixPattern.substring(pos, i), localized); jtulach@1334: } jtulach@1334: char c = affixPattern.charAt(++i); jtulach@1334: ++i; jtulach@1334: if (c == QUOTE) { jtulach@1334: buffer.append(c); jtulach@1334: // Fall through and append another QUOTE below jtulach@1334: } else if (c == CURRENCY_SIGN && jtulach@1334: i= 0 jtulach@1334: || affix.indexOf(symbols.getGroupingSeparator()) >= 0 jtulach@1334: || affix.indexOf(symbols.getDecimalSeparator()) >= 0 jtulach@1334: || affix.indexOf(symbols.getPercent()) >= 0 jtulach@1334: || affix.indexOf(symbols.getPerMill()) >= 0 jtulach@1334: || affix.indexOf(symbols.getDigit()) >= 0 jtulach@1334: || affix.indexOf(symbols.getPatternSeparator()) >= 0 jtulach@1334: || affix.indexOf(symbols.getMinusSign()) >= 0 jtulach@1334: || affix.indexOf(CURRENCY_SIGN) >= 0; jtulach@1334: } jtulach@1334: else { jtulach@1334: needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0 jtulach@1334: || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0 jtulach@1334: || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0 jtulach@1334: || affix.indexOf(PATTERN_PERCENT) >= 0 jtulach@1334: || affix.indexOf(PATTERN_PER_MILLE) >= 0 jtulach@1334: || affix.indexOf(PATTERN_DIGIT) >= 0 jtulach@1334: || affix.indexOf(PATTERN_SEPARATOR) >= 0 jtulach@1334: || affix.indexOf(PATTERN_MINUS) >= 0 jtulach@1334: || affix.indexOf(CURRENCY_SIGN) >= 0; jtulach@1334: } jtulach@1334: if (needQuote) buffer.append('\''); jtulach@1334: if (affix.indexOf('\'') < 0) buffer.append(affix); jtulach@1334: else { jtulach@1334: for (int j=0; j= 0; --j) { jtulach@1334: if (j == 1) jtulach@1334: appendAffix(result, posPrefixPattern, positivePrefix, localized); jtulach@1334: else appendAffix(result, negPrefixPattern, negativePrefix, localized); jtulach@1334: int i; jtulach@1334: int digitCount = useExponentialNotation jtulach@1334: ? getMaximumIntegerDigits() jtulach@1334: : Math.max(groupingSize, getMinimumIntegerDigits())+1; jtulach@1334: for (i = digitCount; i > 0; --i) { jtulach@1334: if (i != digitCount && isGroupingUsed() && groupingSize != 0 && jtulach@1334: i % groupingSize == 0) { jtulach@1334: result.append(localized ? symbols.getGroupingSeparator() : jtulach@1334: PATTERN_GROUPING_SEPARATOR); jtulach@1334: } jtulach@1334: result.append(i <= getMinimumIntegerDigits() jtulach@1334: ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) jtulach@1334: : (localized ? symbols.getDigit() : PATTERN_DIGIT)); jtulach@1334: } jtulach@1334: if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) jtulach@1334: result.append(localized ? symbols.getDecimalSeparator() : jtulach@1334: PATTERN_DECIMAL_SEPARATOR); jtulach@1334: for (i = 0; i < getMaximumFractionDigits(); ++i) { jtulach@1334: if (i < getMinimumFractionDigits()) { jtulach@1334: result.append(localized ? symbols.getZeroDigit() : jtulach@1334: PATTERN_ZERO_DIGIT); jtulach@1334: } else { jtulach@1334: result.append(localized ? symbols.getDigit() : jtulach@1334: PATTERN_DIGIT); jtulach@1334: } jtulach@1334: } jtulach@1334: if (useExponentialNotation) jtulach@1334: { jtulach@1334: result.append(localized ? symbols.getExponentSeparator() : jtulach@1334: PATTERN_EXPONENT); jtulach@1334: for (i=0; i jtulach@1334: * There is no limit to integer digits set jtulach@1334: * by this routine, since that is the typical end-user desire; jtulach@1334: * use setMaximumInteger if you want to set a real value. jtulach@1334: * For negative numbers, use a second pattern, separated by a semicolon jtulach@1334: *

Example "#,#00.0#" -> 1,234.56 jtulach@1334: *

This means a minimum of 2 integer digits, 1 fraction digit, and jtulach@1334: * a maximum of 2 fraction digits. jtulach@1334: *

Example: "#,#00.0#;(#,#00.0#)" for negatives in jtulach@1334: * parentheses. jtulach@1334: *

In negative patterns, the minimum and maximum counts are ignored; jtulach@1334: * these are presumed to be set in the positive pattern. jtulach@1334: * jtulach@1334: * @exception NullPointerException if pattern is null jtulach@1334: * @exception IllegalArgumentException if the given pattern is invalid. jtulach@1334: */ jtulach@1334: public void applyPattern(String pattern) { jtulach@1334: applyPattern(pattern, false); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Apply the given pattern to this Format object. The pattern jtulach@1334: * is assumed to be in a localized notation. A pattern is a jtulach@1334: * short-hand specification for the various formatting properties. jtulach@1334: * These properties can also be changed individually through the jtulach@1334: * various setter methods. jtulach@1334: *

jtulach@1334: * There is no limit to integer digits set jtulach@1334: * by this routine, since that is the typical end-user desire; jtulach@1334: * use setMaximumInteger if you want to set a real value. jtulach@1334: * For negative numbers, use a second pattern, separated by a semicolon jtulach@1334: *

Example "#,#00.0#" -> 1,234.56 jtulach@1334: *

This means a minimum of 2 integer digits, 1 fraction digit, and jtulach@1334: * a maximum of 2 fraction digits. jtulach@1334: *

Example: "#,#00.0#;(#,#00.0#)" for negatives in jtulach@1334: * parentheses. jtulach@1334: *

In negative patterns, the minimum and maximum counts are ignored; jtulach@1334: * these are presumed to be set in the positive pattern. jtulach@1334: * jtulach@1334: * @exception NullPointerException if pattern is null jtulach@1334: * @exception IllegalArgumentException if the given pattern is invalid. jtulach@1334: */ jtulach@1334: public void applyLocalizedPattern(String pattern) { jtulach@1334: applyPattern(pattern, true); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Does the real work of applying a pattern. jtulach@1334: */ jtulach@1334: private void applyPattern(String pattern, boolean localized) { jtulach@1334: char zeroDigit = PATTERN_ZERO_DIGIT; jtulach@1334: char groupingSeparator = PATTERN_GROUPING_SEPARATOR; jtulach@1334: char decimalSeparator = PATTERN_DECIMAL_SEPARATOR; jtulach@1334: char percent = PATTERN_PERCENT; jtulach@1334: char perMill = PATTERN_PER_MILLE; jtulach@1334: char digit = PATTERN_DIGIT; jtulach@1334: char separator = PATTERN_SEPARATOR; jtulach@1334: String exponent = PATTERN_EXPONENT; jtulach@1334: char minus = PATTERN_MINUS; jtulach@1334: if (localized) { jtulach@1334: zeroDigit = symbols.getZeroDigit(); jtulach@1334: groupingSeparator = symbols.getGroupingSeparator(); jtulach@1334: decimalSeparator = symbols.getDecimalSeparator(); jtulach@1334: percent = symbols.getPercent(); jtulach@1334: perMill = symbols.getPerMill(); jtulach@1334: digit = symbols.getDigit(); jtulach@1334: separator = symbols.getPatternSeparator(); jtulach@1334: exponent = symbols.getExponentSeparator(); jtulach@1334: minus = symbols.getMinusSign(); jtulach@1334: } jtulach@1334: boolean gotNegative = false; jtulach@1334: decimalSeparatorAlwaysShown = false; jtulach@1334: isCurrencyFormat = false; jtulach@1334: useExponentialNotation = false; jtulach@1334: jtulach@1334: // Two variables are used to record the subrange of the pattern jtulach@1334: // occupied by phase 1. This is used during the processing of the jtulach@1334: // second pattern (the one representing negative numbers) to ensure jtulach@1334: // that no deviation exists in phase 1 between the two patterns. jtulach@1334: int phaseOneStart = 0; jtulach@1334: int phaseOneLength = 0; jtulach@1334: jtulach@1334: int start = 0; jtulach@1334: for (int j = 1; j >= 0 && start < pattern.length(); --j) { jtulach@1334: boolean inQuote = false; jtulach@1334: StringBuffer prefix = new StringBuffer(); jtulach@1334: StringBuffer suffix = new StringBuffer(); jtulach@1334: int decimalPos = -1; jtulach@1334: int multiplier = 1; jtulach@1334: int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0; jtulach@1334: byte groupingCount = -1; jtulach@1334: jtulach@1334: // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is jtulach@1334: // the section of the pattern with digits, decimal separator, jtulach@1334: // grouping characters. Phase 2 is the suffix. In phases 0 and 2, jtulach@1334: // percent, per mille, and currency symbols are recognized and jtulach@1334: // translated. The separation of the characters into phases is jtulach@1334: // strictly enforced; if phase 1 characters are to appear in the jtulach@1334: // suffix, for example, they must be quoted. jtulach@1334: int phase = 0; jtulach@1334: jtulach@1334: // The affix is either the prefix or the suffix. jtulach@1334: StringBuffer affix = prefix; jtulach@1334: jtulach@1334: for (int pos = start; pos < pattern.length(); ++pos) { jtulach@1334: char ch = pattern.charAt(pos); jtulach@1334: switch (phase) { jtulach@1334: case 0: jtulach@1334: case 2: jtulach@1334: // Process the prefix / suffix characters jtulach@1334: if (inQuote) { jtulach@1334: // A quote within quotes indicates either the closing jtulach@1334: // quote or two quotes, which is a quote literal. That jtulach@1334: // is, we have the second quote in 'do' or 'don''t'. jtulach@1334: if (ch == QUOTE) { jtulach@1334: if ((pos+1) < pattern.length() && jtulach@1334: pattern.charAt(pos+1) == QUOTE) { jtulach@1334: ++pos; jtulach@1334: affix.append("''"); // 'don''t' jtulach@1334: } else { jtulach@1334: inQuote = false; // 'do' jtulach@1334: } jtulach@1334: continue; jtulach@1334: } jtulach@1334: } else { jtulach@1334: // Process unquoted characters seen in prefix or suffix jtulach@1334: // phase. jtulach@1334: if (ch == digit || jtulach@1334: ch == zeroDigit || jtulach@1334: ch == groupingSeparator || jtulach@1334: ch == decimalSeparator) { jtulach@1334: phase = 1; jtulach@1334: if (j == 1) { jtulach@1334: phaseOneStart = pos; jtulach@1334: } jtulach@1334: --pos; // Reprocess this character jtulach@1334: continue; jtulach@1334: } else if (ch == CURRENCY_SIGN) { jtulach@1334: // Use lookahead to determine if the currency sign jtulach@1334: // is doubled or not. jtulach@1334: boolean doubled = (pos + 1) < pattern.length() && jtulach@1334: pattern.charAt(pos + 1) == CURRENCY_SIGN; jtulach@1334: if (doubled) { // Skip over the doubled character jtulach@1334: ++pos; jtulach@1334: } jtulach@1334: isCurrencyFormat = true; jtulach@1334: affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4"); jtulach@1334: continue; jtulach@1334: } else if (ch == QUOTE) { jtulach@1334: // A quote outside quotes indicates either the jtulach@1334: // opening quote or two quotes, which is a quote jtulach@1334: // literal. That is, we have the first quote in 'do' jtulach@1334: // or o''clock. jtulach@1334: if (ch == QUOTE) { jtulach@1334: if ((pos+1) < pattern.length() && jtulach@1334: pattern.charAt(pos+1) == QUOTE) { jtulach@1334: ++pos; jtulach@1334: affix.append("''"); // o''clock jtulach@1334: } else { jtulach@1334: inQuote = true; // 'do' jtulach@1334: } jtulach@1334: continue; jtulach@1334: } jtulach@1334: } else if (ch == separator) { jtulach@1334: // Don't allow separators before we see digit jtulach@1334: // characters of phase 1, and don't allow separators jtulach@1334: // in the second pattern (j == 0). jtulach@1334: if (phase == 0 || j == 0) { jtulach@1334: throw new IllegalArgumentException("Unquoted special character '" + jtulach@1334: ch + "' in pattern \"" + pattern + '"'); jtulach@1334: } jtulach@1334: start = pos + 1; jtulach@1334: pos = pattern.length(); jtulach@1334: continue; jtulach@1334: } jtulach@1334: jtulach@1334: // Next handle characters which are appended directly. jtulach@1334: else if (ch == percent) { jtulach@1334: if (multiplier != 1) { jtulach@1334: throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + jtulach@1334: pattern + '"'); jtulach@1334: } jtulach@1334: multiplier = 100; jtulach@1334: affix.append("'%"); jtulach@1334: continue; jtulach@1334: } else if (ch == perMill) { jtulach@1334: if (multiplier != 1) { jtulach@1334: throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" + jtulach@1334: pattern + '"'); jtulach@1334: } jtulach@1334: multiplier = 1000; jtulach@1334: affix.append("'\u2030"); jtulach@1334: continue; jtulach@1334: } else if (ch == minus) { jtulach@1334: affix.append("'-"); jtulach@1334: continue; jtulach@1334: } jtulach@1334: } jtulach@1334: // Note that if we are within quotes, or if this is an jtulach@1334: // unquoted, non-special character, then we usually fall jtulach@1334: // through to here. jtulach@1334: affix.append(ch); jtulach@1334: break; jtulach@1334: jtulach@1334: case 1: jtulach@1334: // Phase one must be identical in the two sub-patterns. We jtulach@1334: // enforce this by doing a direct comparison. While jtulach@1334: // processing the first sub-pattern, we just record its jtulach@1334: // length. While processing the second, we compare jtulach@1334: // characters. jtulach@1334: if (j == 1) { jtulach@1334: ++phaseOneLength; jtulach@1334: } else { jtulach@1334: if (--phaseOneLength == 0) { jtulach@1334: phase = 2; jtulach@1334: affix = suffix; jtulach@1334: } jtulach@1334: continue; jtulach@1334: } jtulach@1334: jtulach@1334: // Process the digits, decimal, and grouping characters. We jtulach@1334: // record five pieces of information. We expect the digits jtulach@1334: // to occur in the pattern ####0000.####, and we record the jtulach@1334: // number of left digits, zero (central) digits, and right jtulach@1334: // digits. The position of the last grouping character is jtulach@1334: // recorded (should be somewhere within the first two blocks jtulach@1334: // of characters), as is the position of the decimal point, jtulach@1334: // if any (should be in the zero digits). If there is no jtulach@1334: // decimal point, then there should be no right digits. jtulach@1334: if (ch == digit) { jtulach@1334: if (zeroDigitCount > 0) { jtulach@1334: ++digitRightCount; jtulach@1334: } else { jtulach@1334: ++digitLeftCount; jtulach@1334: } jtulach@1334: if (groupingCount >= 0 && decimalPos < 0) { jtulach@1334: ++groupingCount; jtulach@1334: } jtulach@1334: } else if (ch == zeroDigit) { jtulach@1334: if (digitRightCount > 0) { jtulach@1334: throw new IllegalArgumentException("Unexpected '0' in pattern \"" + jtulach@1334: pattern + '"'); jtulach@1334: } jtulach@1334: ++zeroDigitCount; jtulach@1334: if (groupingCount >= 0 && decimalPos < 0) { jtulach@1334: ++groupingCount; jtulach@1334: } jtulach@1334: } else if (ch == groupingSeparator) { jtulach@1334: groupingCount = 0; jtulach@1334: } else if (ch == decimalSeparator) { jtulach@1334: if (decimalPos >= 0) { jtulach@1334: throw new IllegalArgumentException("Multiple decimal separators in pattern \"" + jtulach@1334: pattern + '"'); jtulach@1334: } jtulach@1334: decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; jtulach@1334: } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){ jtulach@1334: if (useExponentialNotation) { jtulach@1334: throw new IllegalArgumentException("Multiple exponential " + jtulach@1334: "symbols in pattern \"" + pattern + '"'); jtulach@1334: } jtulach@1334: useExponentialNotation = true; jtulach@1334: minExponentDigits = 0; jtulach@1334: jtulach@1334: // Use lookahead to parse out the exponential part jtulach@1334: // of the pattern, then jump into phase 2. jtulach@1334: pos = pos+exponent.length(); jtulach@1334: while (pos < pattern.length() && jtulach@1334: pattern.charAt(pos) == zeroDigit) { jtulach@1334: ++minExponentDigits; jtulach@1334: ++phaseOneLength; jtulach@1334: ++pos; jtulach@1334: } jtulach@1334: jtulach@1334: if ((digitLeftCount + zeroDigitCount) < 1 || jtulach@1334: minExponentDigits < 1) { jtulach@1334: throw new IllegalArgumentException("Malformed exponential " + jtulach@1334: "pattern \"" + pattern + '"'); jtulach@1334: } jtulach@1334: jtulach@1334: // Transition to phase 2 jtulach@1334: phase = 2; jtulach@1334: affix = suffix; jtulach@1334: --pos; jtulach@1334: continue; jtulach@1334: } else { jtulach@1334: phase = 2; jtulach@1334: affix = suffix; jtulach@1334: --pos; jtulach@1334: --phaseOneLength; jtulach@1334: continue; jtulach@1334: } jtulach@1334: break; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: // Handle patterns with no '0' pattern character. These patterns jtulach@1334: // are legal, but must be interpreted. "##.###" -> "#0.###". jtulach@1334: // ".###" -> ".0##". jtulach@1334: /* We allow patterns of the form "####" to produce a zeroDigitCount jtulach@1334: * of zero (got that?); although this seems like it might make it jtulach@1334: * possible for format() to produce empty strings, format() checks jtulach@1334: * for this condition and outputs a zero digit in this situation. jtulach@1334: * Having a zeroDigitCount of zero yields a minimum integer digits jtulach@1334: * of zero, which allows proper round-trip patterns. That is, we jtulach@1334: * don't want "#" to become "#0" when toPattern() is called (even jtulach@1334: * though that's what it really is, semantically). jtulach@1334: */ jtulach@1334: if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { jtulach@1334: // Handle "###.###" and "###." and ".###" jtulach@1334: int n = decimalPos; jtulach@1334: if (n == 0) { // Handle ".###" jtulach@1334: ++n; jtulach@1334: } jtulach@1334: digitRightCount = digitLeftCount - n; jtulach@1334: digitLeftCount = n - 1; jtulach@1334: zeroDigitCount = 1; jtulach@1334: } jtulach@1334: jtulach@1334: // Do syntax checking on the digits. jtulach@1334: if ((decimalPos < 0 && digitRightCount > 0) || jtulach@1334: (decimalPos >= 0 && (decimalPos < digitLeftCount || jtulach@1334: decimalPos > (digitLeftCount + zeroDigitCount))) || jtulach@1334: groupingCount == 0 || inQuote) { jtulach@1334: throw new IllegalArgumentException("Malformed pattern \"" + jtulach@1334: pattern + '"'); jtulach@1334: } jtulach@1334: jtulach@1334: if (j == 1) { jtulach@1334: posPrefixPattern = prefix.toString(); jtulach@1334: posSuffixPattern = suffix.toString(); jtulach@1334: negPrefixPattern = posPrefixPattern; // assume these for now jtulach@1334: negSuffixPattern = posSuffixPattern; jtulach@1334: int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; jtulach@1334: /* The effectiveDecimalPos is the position the decimal is at or jtulach@1334: * would be at if there is no decimal. Note that if decimalPos<0, jtulach@1334: * then digitTotalCount == digitLeftCount + zeroDigitCount. jtulach@1334: */ jtulach@1334: int effectiveDecimalPos = decimalPos >= 0 ? jtulach@1334: decimalPos : digitTotalCount; jtulach@1334: setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount); jtulach@1334: setMaximumIntegerDigits(useExponentialNotation ? jtulach@1334: digitLeftCount + getMinimumIntegerDigits() : jtulach@1334: MAXIMUM_INTEGER_DIGITS); jtulach@1334: setMaximumFractionDigits(decimalPos >= 0 ? jtulach@1334: (digitTotalCount - decimalPos) : 0); jtulach@1334: setMinimumFractionDigits(decimalPos >= 0 ? jtulach@1334: (digitLeftCount + zeroDigitCount - decimalPos) : 0); jtulach@1334: setGroupingUsed(groupingCount > 0); jtulach@1334: this.groupingSize = (groupingCount > 0) ? groupingCount : 0; jtulach@1334: this.multiplier = multiplier; jtulach@1334: setDecimalSeparatorAlwaysShown(decimalPos == 0 || jtulach@1334: decimalPos == digitTotalCount); jtulach@1334: } else { jtulach@1334: negPrefixPattern = prefix.toString(); jtulach@1334: negSuffixPattern = suffix.toString(); jtulach@1334: gotNegative = true; jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: if (pattern.length() == 0) { jtulach@1334: posPrefixPattern = posSuffixPattern = ""; jtulach@1334: setMinimumIntegerDigits(0); jtulach@1334: setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS); jtulach@1334: setMinimumFractionDigits(0); jtulach@1334: setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS); jtulach@1334: } jtulach@1334: jtulach@1334: // If there was no negative pattern, or if the negative pattern is jtulach@1334: // identical to the positive pattern, then prepend the minus sign to jtulach@1334: // the positive pattern to form the negative pattern. jtulach@1334: if (!gotNegative || jtulach@1334: (negPrefixPattern.equals(posPrefixPattern) jtulach@1334: && negSuffixPattern.equals(posSuffixPattern))) { jtulach@1334: negSuffixPattern = posSuffixPattern; jtulach@1334: negPrefixPattern = "'-" + posPrefixPattern; jtulach@1334: } jtulach@1334: jtulach@1334: expandAffixes(); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the maximum number of digits allowed in the integer portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of newValue and jtulach@1334: * 309 is used. Negative input values are replaced with 0. jtulach@1334: * @see NumberFormat#setMaximumIntegerDigits jtulach@1334: */ jtulach@1334: public void setMaximumIntegerDigits(int newValue) { jtulach@1334: maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); jtulach@1334: super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? jtulach@1334: DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); jtulach@1334: if (minimumIntegerDigits > maximumIntegerDigits) { jtulach@1334: minimumIntegerDigits = maximumIntegerDigits; jtulach@1334: super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? jtulach@1334: DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the minimum number of digits allowed in the integer portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of newValue and jtulach@1334: * 309 is used. Negative input values are replaced with 0. jtulach@1334: * @see NumberFormat#setMinimumIntegerDigits jtulach@1334: */ jtulach@1334: public void setMinimumIntegerDigits(int newValue) { jtulach@1334: minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); jtulach@1334: super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? jtulach@1334: DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); jtulach@1334: if (minimumIntegerDigits > maximumIntegerDigits) { jtulach@1334: maximumIntegerDigits = minimumIntegerDigits; jtulach@1334: super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? jtulach@1334: DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the maximum number of digits allowed in the fraction portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of newValue and jtulach@1334: * 340 is used. Negative input values are replaced with 0. jtulach@1334: * @see NumberFormat#setMaximumFractionDigits jtulach@1334: */ jtulach@1334: public void setMaximumFractionDigits(int newValue) { jtulach@1334: maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); jtulach@1334: super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? jtulach@1334: DOUBLE_FRACTION_DIGITS : maximumFractionDigits); jtulach@1334: if (minimumFractionDigits > maximumFractionDigits) { jtulach@1334: minimumFractionDigits = maximumFractionDigits; jtulach@1334: super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? jtulach@1334: DOUBLE_FRACTION_DIGITS : minimumFractionDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the minimum number of digits allowed in the fraction portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of newValue and jtulach@1334: * 340 is used. Negative input values are replaced with 0. jtulach@1334: * @see NumberFormat#setMinimumFractionDigits jtulach@1334: */ jtulach@1334: public void setMinimumFractionDigits(int newValue) { jtulach@1334: minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); jtulach@1334: super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? jtulach@1334: DOUBLE_FRACTION_DIGITS : minimumFractionDigits); jtulach@1334: if (minimumFractionDigits > maximumFractionDigits) { jtulach@1334: maximumFractionDigits = minimumFractionDigits; jtulach@1334: super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? jtulach@1334: DOUBLE_FRACTION_DIGITS : maximumFractionDigits); jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the maximum number of digits allowed in the integer portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of the return value and jtulach@1334: * 309 is used. jtulach@1334: * @see #setMaximumIntegerDigits jtulach@1334: */ jtulach@1334: public int getMaximumIntegerDigits() { jtulach@1334: return maximumIntegerDigits; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the minimum number of digits allowed in the integer portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of the return value and jtulach@1334: * 309 is used. jtulach@1334: * @see #setMinimumIntegerDigits jtulach@1334: */ jtulach@1334: public int getMinimumIntegerDigits() { jtulach@1334: return minimumIntegerDigits; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the maximum number of digits allowed in the fraction portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of the return value and jtulach@1334: * 340 is used. jtulach@1334: * @see #setMaximumFractionDigits jtulach@1334: */ jtulach@1334: public int getMaximumFractionDigits() { jtulach@1334: return maximumFractionDigits; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the minimum number of digits allowed in the fraction portion of a jtulach@1334: * number. jtulach@1334: * For formatting numbers other than BigInteger and jtulach@1334: * BigDecimal objects, the lower of the return value and jtulach@1334: * 340 is used. jtulach@1334: * @see #setMinimumFractionDigits jtulach@1334: */ jtulach@1334: public int getMinimumFractionDigits() { jtulach@1334: return minimumFractionDigits; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the currency used by this decimal format when formatting jtulach@1334: * currency values. jtulach@1334: * The currency is obtained by calling jtulach@1334: * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency} jtulach@1334: * on this number format's symbols. jtulach@1334: * jtulach@1334: * @return the currency used by this decimal format, or null jtulach@1334: * @since 1.4 jtulach@1334: */ jtulach@1334: public Currency getCurrency() { jtulach@1334: return symbols.getCurrency(); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the currency used by this number format when formatting jtulach@1334: * currency values. This does not update the minimum or maximum jtulach@1334: * number of fraction digits used by the number format. jtulach@1334: * The currency is set by calling jtulach@1334: * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency} jtulach@1334: * on this number format's symbols. jtulach@1334: * jtulach@1334: * @param currency the new currency to be used by this decimal format jtulach@1334: * @exception NullPointerException if currency is null jtulach@1334: * @since 1.4 jtulach@1334: */ jtulach@1334: public void setCurrency(Currency currency) { jtulach@1334: if (currency != symbols.getCurrency()) { jtulach@1334: symbols.setCurrency(currency); jtulach@1334: if (isCurrencyFormat) { jtulach@1334: expandAffixes(); jtulach@1334: } jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Gets the {@link java.math.RoundingMode} used in this DecimalFormat. jtulach@1334: * jtulach@1334: * @return The RoundingMode used for this DecimalFormat. jtulach@1334: * @see #setRoundingMode(RoundingMode) jtulach@1334: * @since 1.6 jtulach@1334: */ jtulach@1334: public RoundingMode getRoundingMode() { jtulach@1334: return roundingMode; jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Sets the {@link java.math.RoundingMode} used in this DecimalFormat. jtulach@1334: * jtulach@1334: * @param roundingMode The RoundingMode to be used jtulach@1334: * @see #getRoundingMode() jtulach@1334: * @exception NullPointerException if roundingMode is null. jtulach@1334: * @since 1.6 jtulach@1334: */ jtulach@1334: public void setRoundingMode(RoundingMode roundingMode) { jtulach@1334: if (roundingMode == null) { jtulach@1334: throw new NullPointerException(); jtulach@1334: } jtulach@1334: jtulach@1334: this.roundingMode = roundingMode; jtulach@1334: digitList.setRoundingMode(roundingMode); jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Adjusts the minimum and maximum fraction digits to values that jtulach@1334: * are reasonable for the currency's default fraction digits. jtulach@1334: */ jtulach@1334: void adjustForCurrencyDefaultFractionDigits() { jtulach@1334: Currency currency = symbols.getCurrency(); jtulach@1334: if (currency == null) { jtulach@1334: try { jtulach@1334: currency = Currency.getInstance(symbols.getInternationalCurrencySymbol()); jtulach@1334: } catch (IllegalArgumentException e) { jtulach@1334: } jtulach@1334: } jtulach@1334: if (currency != null) { jtulach@1334: int digits = currency.getDefaultFractionDigits(); jtulach@1334: if (digits != -1) { jtulach@1334: int oldMinDigits = getMinimumFractionDigits(); jtulach@1334: // Common patterns are "#.##", "#.00", "#". jtulach@1334: // Try to adjust all of them in a reasonable way. jtulach@1334: if (oldMinDigits == getMaximumFractionDigits()) { jtulach@1334: setMinimumFractionDigits(digits); jtulach@1334: setMaximumFractionDigits(digits); jtulach@1334: } else { jtulach@1334: setMinimumFractionDigits(Math.min(digits, oldMinDigits)); jtulach@1334: setMaximumFractionDigits(digits); jtulach@1334: } jtulach@1334: } jtulach@1334: } jtulach@1334: } jtulach@1334: jtulach@1334: /** jtulach@1334: * Reads the default serializable fields from the stream and performs jtulach@1334: * validations and adjustments for older serialized versions. The jtulach@1334: * validations and adjustments are: jtulach@1334: *

    jtulach@1334: *
  1. jtulach@1334: * Verify that the superclass's digit count fields correctly reflect jtulach@1334: * the limits imposed on formatting numbers other than jtulach@1334: * BigInteger and BigDecimal objects. These jtulach@1334: * limits are stored in the superclass for serialization compatibility jtulach@1334: * with older versions, while the limits for BigInteger and jtulach@1334: * BigDecimal objects are kept in this class. jtulach@1334: * If, in the superclass, the minimum or maximum integer digit count is jtulach@1334: * larger than DOUBLE_INTEGER_DIGITS or if the minimum or jtulach@1334: * maximum fraction digit count is larger than jtulach@1334: * DOUBLE_FRACTION_DIGITS, then the stream data is invalid jtulach@1334: * and this method throws an InvalidObjectException. jtulach@1334: *
  2. jtulach@1334: * If serialVersionOnStream is less than 4, initialize jtulach@1334: * roundingMode to {@link java.math.RoundingMode#HALF_EVEN jtulach@1334: * RoundingMode.HALF_EVEN}. This field is new with version 4. jtulach@1334: *
  3. jtulach@1334: * If serialVersionOnStream is less than 3, then call jtulach@1334: * the setters for the minimum and maximum integer and fraction digits with jtulach@1334: * the values of the corresponding superclass getters to initialize the jtulach@1334: * fields in this class. The fields in this class are new with version 3. jtulach@1334: *
  4. jtulach@1334: * If serialVersionOnStream is less than 1, indicating that jtulach@1334: * the stream was written by JDK 1.1, initialize jtulach@1334: * useExponentialNotation jtulach@1334: * to false, since it was not present in JDK 1.1. jtulach@1334: *
  5. jtulach@1334: * Set serialVersionOnStream to the maximum allowed value so jtulach@1334: * that default serialization will work properly if this object is streamed jtulach@1334: * out again. jtulach@1334: *
jtulach@1334: * jtulach@1334: *

Stream versions older than 2 will not have the affix pattern variables jtulach@1334: * posPrefixPattern etc. As a result, they will be initialized jtulach@1334: * to null, which means the affix strings will be taken as jtulach@1334: * literal values. This is exactly what we want, since that corresponds to jtulach@1334: * the pre-version-2 behavior. jtulach@1334: */ jtulach@1334: private void readObject(ObjectInputStream stream) jtulach@1334: throws IOException, ClassNotFoundException jtulach@1334: { jtulach@1334: stream.defaultReadObject(); jtulach@1334: digitList = new DigitList(); jtulach@1334: jtulach@1334: if (serialVersionOnStream < 4) { jtulach@1334: setRoundingMode(RoundingMode.HALF_EVEN); jtulach@1334: } jtulach@1334: // We only need to check the maximum counts because NumberFormat jtulach@1334: // .readObject has already ensured that the maximum is greater than the jtulach@1334: // minimum count. jtulach@1334: if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS || jtulach@1334: super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { jtulach@1334: throw new InvalidObjectException("Digit count out of range"); jtulach@1334: } jtulach@1334: if (serialVersionOnStream < 3) { jtulach@1334: setMaximumIntegerDigits(super.getMaximumIntegerDigits()); jtulach@1334: setMinimumIntegerDigits(super.getMinimumIntegerDigits()); jtulach@1334: setMaximumFractionDigits(super.getMaximumFractionDigits()); jtulach@1334: setMinimumFractionDigits(super.getMinimumFractionDigits()); jtulach@1334: } jtulach@1334: if (serialVersionOnStream < 1) { jtulach@1334: // Didn't have exponential fields jtulach@1334: useExponentialNotation = false; jtulach@1334: } jtulach@1334: serialVersionOnStream = currentSerialVersion; jtulach@1334: } jtulach@1334: jtulach@1334: //---------------------------------------------------------------------- jtulach@1334: // INSTANCE VARIABLES jtulach@1334: //---------------------------------------------------------------------- jtulach@1334: jtulach@1334: private transient DigitList digitList = new DigitList(); jtulach@1334: jtulach@1334: /** jtulach@1334: * The symbol used as a prefix when formatting positive numbers, e.g. "+". jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getPositivePrefix jtulach@1334: */ jtulach@1334: private String positivePrefix = ""; jtulach@1334: jtulach@1334: /** jtulach@1334: * The symbol used as a suffix when formatting positive numbers. jtulach@1334: * This is often an empty string. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getPositiveSuffix jtulach@1334: */ jtulach@1334: private String positiveSuffix = ""; jtulach@1334: jtulach@1334: /** jtulach@1334: * The symbol used as a prefix when formatting negative numbers, e.g. "-". jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getNegativePrefix jtulach@1334: */ jtulach@1334: private String negativePrefix = "-"; jtulach@1334: jtulach@1334: /** jtulach@1334: * The symbol used as a suffix when formatting negative numbers. jtulach@1334: * This is often an empty string. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getNegativeSuffix jtulach@1334: */ jtulach@1334: private String negativeSuffix = ""; jtulach@1334: jtulach@1334: /** jtulach@1334: * The prefix pattern for non-negative numbers. This variable corresponds jtulach@1334: * to positivePrefix. jtulach@1334: * jtulach@1334: *

This pattern is expanded by the method expandAffix() to jtulach@1334: * positivePrefix to update the latter to reflect changes in jtulach@1334: * symbols. If this variable is null then jtulach@1334: * positivePrefix is taken as a literal value that does not jtulach@1334: * change when symbols changes. This variable is always jtulach@1334: * null for DecimalFormat objects older than jtulach@1334: * stream version 2 restored from stream. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.3 jtulach@1334: */ jtulach@1334: private String posPrefixPattern; jtulach@1334: jtulach@1334: /** jtulach@1334: * The suffix pattern for non-negative numbers. This variable corresponds jtulach@1334: * to positiveSuffix. This variable is analogous to jtulach@1334: * posPrefixPattern; see that variable for further jtulach@1334: * documentation. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.3 jtulach@1334: */ jtulach@1334: private String posSuffixPattern; jtulach@1334: jtulach@1334: /** jtulach@1334: * The prefix pattern for negative numbers. This variable corresponds jtulach@1334: * to negativePrefix. This variable is analogous to jtulach@1334: * posPrefixPattern; see that variable for further jtulach@1334: * documentation. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.3 jtulach@1334: */ jtulach@1334: private String negPrefixPattern; jtulach@1334: jtulach@1334: /** jtulach@1334: * The suffix pattern for negative numbers. This variable corresponds jtulach@1334: * to negativeSuffix. This variable is analogous to jtulach@1334: * posPrefixPattern; see that variable for further jtulach@1334: * documentation. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.3 jtulach@1334: */ jtulach@1334: private String negSuffixPattern; jtulach@1334: jtulach@1334: /** jtulach@1334: * The multiplier for use in percent, per mille, etc. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getMultiplier jtulach@1334: */ jtulach@1334: private int multiplier = 1; jtulach@1334: jtulach@1334: /** jtulach@1334: * The number of digits between grouping separators in the integer jtulach@1334: * portion of a number. Must be greater than 0 if jtulach@1334: * NumberFormat.groupingUsed is true. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getGroupingSize jtulach@1334: * @see java.text.NumberFormat#isGroupingUsed jtulach@1334: */ jtulach@1334: private byte groupingSize = 3; // invariant, > 0 if useThousands jtulach@1334: jtulach@1334: /** jtulach@1334: * If true, forces the decimal separator to always appear in a formatted jtulach@1334: * number, even if the fractional part of the number is zero. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #isDecimalSeparatorAlwaysShown jtulach@1334: */ jtulach@1334: private boolean decimalSeparatorAlwaysShown = false; jtulach@1334: jtulach@1334: /** jtulach@1334: * If true, parse returns BigDecimal wherever possible. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #isParseBigDecimal jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: private boolean parseBigDecimal = false; jtulach@1334: jtulach@1334: jtulach@1334: /** jtulach@1334: * True if this object represents a currency format. This determines jtulach@1334: * whether the monetary decimal separator is used instead of the normal one. jtulach@1334: */ jtulach@1334: private transient boolean isCurrencyFormat = false; jtulach@1334: jtulach@1334: /** jtulach@1334: * The DecimalFormatSymbols object used by this format. jtulach@1334: * It contains the symbols used to format numbers, e.g. the grouping separator, jtulach@1334: * decimal separator, and so on. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #setDecimalFormatSymbols jtulach@1334: * @see java.text.DecimalFormatSymbols jtulach@1334: */ jtulach@1334: private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); jtulach@1334: jtulach@1334: /** jtulach@1334: * True to force the use of exponential (i.e. scientific) notation when formatting jtulach@1334: * numbers. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.2 jtulach@1334: */ jtulach@1334: private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2 jtulach@1334: jtulach@1334: /** jtulach@1334: * FieldPositions describing the positive prefix String. This is jtulach@1334: * lazily created. Use getPositivePrefixFieldPositions jtulach@1334: * when needed. jtulach@1334: */ jtulach@1334: private transient FieldPosition[] positivePrefixFieldPositions; jtulach@1334: jtulach@1334: /** jtulach@1334: * FieldPositions describing the positive suffix String. This is jtulach@1334: * lazily created. Use getPositiveSuffixFieldPositions jtulach@1334: * when needed. jtulach@1334: */ jtulach@1334: private transient FieldPosition[] positiveSuffixFieldPositions; jtulach@1334: jtulach@1334: /** jtulach@1334: * FieldPositions describing the negative prefix String. This is jtulach@1334: * lazily created. Use getNegativePrefixFieldPositions jtulach@1334: * when needed. jtulach@1334: */ jtulach@1334: private transient FieldPosition[] negativePrefixFieldPositions; jtulach@1334: jtulach@1334: /** jtulach@1334: * FieldPositions describing the negative suffix String. This is jtulach@1334: * lazily created. Use getNegativeSuffixFieldPositions jtulach@1334: * when needed. jtulach@1334: */ jtulach@1334: private transient FieldPosition[] negativeSuffixFieldPositions; jtulach@1334: jtulach@1334: /** jtulach@1334: * The minimum number of digits used to display the exponent when a number is jtulach@1334: * formatted in exponential notation. This field is ignored if jtulach@1334: * useExponentialNotation is not true. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.2 jtulach@1334: */ jtulach@1334: private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2 jtulach@1334: jtulach@1334: /** jtulach@1334: * The maximum number of digits allowed in the integer portion of a jtulach@1334: * BigInteger or BigDecimal number. jtulach@1334: * maximumIntegerDigits must be greater than or equal to jtulach@1334: * minimumIntegerDigits. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getMaximumIntegerDigits jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: private int maximumIntegerDigits = super.getMaximumIntegerDigits(); jtulach@1334: jtulach@1334: /** jtulach@1334: * The minimum number of digits allowed in the integer portion of a jtulach@1334: * BigInteger or BigDecimal number. jtulach@1334: * minimumIntegerDigits must be less than or equal to jtulach@1334: * maximumIntegerDigits. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getMinimumIntegerDigits jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: private int minimumIntegerDigits = super.getMinimumIntegerDigits(); jtulach@1334: jtulach@1334: /** jtulach@1334: * The maximum number of digits allowed in the fractional portion of a jtulach@1334: * BigInteger or BigDecimal number. jtulach@1334: * maximumFractionDigits must be greater than or equal to jtulach@1334: * minimumFractionDigits. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getMaximumFractionDigits jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: private int maximumFractionDigits = super.getMaximumFractionDigits(); jtulach@1334: jtulach@1334: /** jtulach@1334: * The minimum number of digits allowed in the fractional portion of a jtulach@1334: * BigInteger or BigDecimal number. jtulach@1334: * minimumFractionDigits must be less than or equal to jtulach@1334: * maximumFractionDigits. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @see #getMinimumFractionDigits jtulach@1334: * @since 1.5 jtulach@1334: */ jtulach@1334: private int minimumFractionDigits = super.getMinimumFractionDigits(); jtulach@1334: jtulach@1334: /** jtulach@1334: * The {@link java.math.RoundingMode} used in this DecimalFormat. jtulach@1334: * jtulach@1334: * @serial jtulach@1334: * @since 1.6 jtulach@1334: */ jtulach@1334: private RoundingMode roundingMode = RoundingMode.HALF_EVEN; jtulach@1334: jtulach@1334: //---------------------------------------------------------------------- jtulach@1334: jtulach@1334: static final int currentSerialVersion = 4; jtulach@1334: jtulach@1334: /** jtulach@1334: * The internal serial version which says which version was written. jtulach@1334: * Possible values are: jtulach@1334: *

jtulach@1334: * @since 1.2 jtulach@1334: * @serial jtulach@1334: */ jtulach@1334: private int serialVersionOnStream = currentSerialVersion; jtulach@1334: jtulach@1334: //---------------------------------------------------------------------- jtulach@1334: // CONSTANTS jtulach@1334: //---------------------------------------------------------------------- jtulach@1334: jtulach@1334: // Constants for characters used in programmatic (unlocalized) patterns. jtulach@1334: private static final char PATTERN_ZERO_DIGIT = '0'; jtulach@1334: private static final char PATTERN_GROUPING_SEPARATOR = ','; jtulach@1334: private static final char PATTERN_DECIMAL_SEPARATOR = '.'; jtulach@1334: private static final char PATTERN_PER_MILLE = '\u2030'; jtulach@1334: private static final char PATTERN_PERCENT = '%'; jtulach@1334: private static final char PATTERN_DIGIT = '#'; jtulach@1334: private static final char PATTERN_SEPARATOR = ';'; jtulach@1334: private static final String PATTERN_EXPONENT = "E"; jtulach@1334: private static final char PATTERN_MINUS = '-'; jtulach@1334: jtulach@1334: /** jtulach@1334: * The CURRENCY_SIGN is the standard Unicode symbol for currency. It jtulach@1334: * is used in patterns and substituted with either the currency symbol, jtulach@1334: * or if it is doubled, with the international currency symbol. If the jtulach@1334: * CURRENCY_SIGN is seen in a pattern, then the decimal separator is jtulach@1334: * replaced with the monetary decimal separator. jtulach@1334: * jtulach@1334: * The CURRENCY_SIGN is not localized. jtulach@1334: */ jtulach@1334: private static final char CURRENCY_SIGN = '\u00A4'; jtulach@1334: jtulach@1334: private static final char QUOTE = '\''; jtulach@1334: jtulach@1334: private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0]; jtulach@1334: jtulach@1334: // Upper limit on integer and fraction digits for a Java double jtulach@1334: static final int DOUBLE_INTEGER_DIGITS = 309; jtulach@1334: static final int DOUBLE_FRACTION_DIGITS = 340; jtulach@1334: jtulach@1334: // Upper limit on integer and fraction digits for BigDecimal and BigInteger jtulach@1334: static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE; jtulach@1334: static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE; jtulach@1334: jtulach@1334: // Proclaim JDK 1.1 serial compatibility. jtulach@1334: static final long serialVersionUID = 864413376551465018L; jtulach@1334: jtulach@1334: /** jtulach@1334: * Cache to hold the NumberPattern of a Locale. jtulach@1334: */ jtulach@1334: private static final ConcurrentMap cachedLocaleData jtulach@1334: = new ConcurrentHashMap(3); jtulach@1334: }