1 /*
2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 * materials are provided under terms of a License Agreement between Taligent
33 * and Sun. This technology is protected by multiple US and International
34 * patents. This notice and attribution to Taligent may not be removed.
35 * Taligent is a registered trademark of Taligent, Inc.
36 *
37 */
38
39 package java.text;
40
41 import java.io.IOException;
42 import java.io.InvalidObjectException;
43 import java.io.ObjectInputStream;
44 import java.math.BigDecimal;
45 import java.math.BigInteger;
46 import java.math.RoundingMode;
47 import java.text.spi.NumberFormatProvider;
48 import java.util.ArrayList;
49 import java.util.Currency;
50 import java.util.Locale;
51 import java.util.ResourceBundle;
52 import java.util.concurrent.ConcurrentHashMap;
53 import java.util.concurrent.ConcurrentMap;
54 import java.util.concurrent.atomic.AtomicInteger;
55 import java.util.concurrent.atomic.AtomicLong;
56 import sun.util.locale.provider.LocaleProviderAdapter;
57 import sun.util.locale.provider.ResourceBundleBasedAdapter;
58
59 /**
60 * <code>DecimalFormat</code> is a concrete subclass of
61 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
62 * features designed to make it possible to parse and format numbers in any
63 * locale, including support for Western, Arabic, and Indic digits. It also
64 * supports different kinds of numbers, including integers (123), fixed-point
65 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
66 * currency amounts ($123). All of these can be localized.
67 *
68 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
69 * default locale, call one of <code>NumberFormat</code>'s factory methods, such
70 * as <code>getInstance()</code>. In general, do not call the
71 * <code>DecimalFormat</code> constructors directly, since the
72 * <code>NumberFormat</code> factory methods may return subclasses other than
73 * <code>DecimalFormat</code>. If you need to customize the format object, do
140 *
141 * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
142 * thousands separators, decimal separators, etc. may be set to arbitrary
143 * values, and they will appear properly during formatting. However, care must
144 * be taken that the symbols and strings do not conflict, or parsing will be
145 * unreliable. For example, either the positive and negative prefixes or the
146 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
147 * to distinguish positive from negative values. (If they are identical, then
148 * <code>DecimalFormat</code> will behave as if no negative subpattern was
149 * specified.) Another example is that the decimal separator and thousands
150 * separator should be distinct characters, or parsing will be impossible.
151 *
152 * <p>The grouping separator is commonly used for thousands, but in some
153 * countries it separates ten-thousands. The grouping size is a constant number
154 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
155 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
156 * interval between the last one and the end of the integer is the one that is
157 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
158 * <code>"##,####,####"</code>.
159 *
160 * <h4>Special Pattern Characters</h4>
161 *
162 * <p>Many characters in a pattern are taken literally; they are matched during
163 * parsing and output unchanged during formatting. Special characters, on the
164 * other hand, stand for other characters, strings, or classes of characters.
165 * They must be quoted, unless noted otherwise, if they are to appear in the
166 * prefix or suffix as literals.
167 *
168 * <p>The characters listed here are used in non-localized patterns. Localized
169 * patterns use the corresponding characters taken from this formatter's
170 * <code>DecimalFormatSymbols</code> object instead, and these characters lose
171 * their special status. Two exceptions are the currency sign and quote, which
172 * are not localized.
173 *
174 * <blockquote>
175 * <table class="striped">
176 * <caption style="display:none">Chart showing symbol, location, localized, and meaning.</caption>
177 * <thead>
178 * <tr>
179 * <th scope="col" style="text-align:left">Symbol
180 * <th scope="col" style="text-align:left">Location
555 String tempResult = fastFormat(number);
556 if (tempResult != null) {
557 result.append(tempResult);
558 return result;
559 }
560 }
561
562 // if fast-path could not work, we fallback to standard code.
563 return format(number, result, fieldPosition.getFieldDelegate());
564 }
565
566 /**
567 * Formats a double to produce a string.
568 * @param number The double to format
569 * @param result where the text is to be appended
570 * @param delegate notified of locations of sub fields
571 * @exception ArithmeticException if rounding is needed with rounding
572 * mode being set to RoundingMode.UNNECESSARY
573 * @return The formatted number string
574 */
575 private StringBuffer format(double number, StringBuffer result,
576 FieldDelegate delegate) {
577 if (Double.isNaN(number) ||
578 (Double.isInfinite(number) && multiplier == 0)) {
579 int iFieldStart = result.length();
580 result.append(symbols.getNaN());
581 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
582 iFieldStart, result.length(), result);
583 return result;
584 }
585
586 /* Detecting whether a double is negative is easy with the exception of
587 * the value -0.0. This is a double which has a zero mantissa (and
588 * exponent), but a negative sign bit. It is semantically distinct from
589 * a zero with a positive sign bit, and this distinction is important
590 * to certain kinds of computations. However, it's a little tricky to
591 * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
592 * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
593 * -Infinity. Proper detection of -0.0 is needed to deal with the
594 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
595 */
596 boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
597
598 if (multiplier != 1) {
599 number *= multiplier;
600 }
601
602 if (Double.isInfinite(number)) {
603 if (isNegative) {
604 append(result, negativePrefix, delegate,
605 getNegativePrefixFieldPositions(), Field.SIGN);
606 } else {
607 append(result, positivePrefix, delegate,
608 getPositivePrefixFieldPositions(), Field.SIGN);
609 }
610
611 int iFieldStart = result.length();
612 result.append(symbols.getInfinity());
613 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
614 iFieldStart, result.length(), result);
615
616 if (isNegative) {
617 append(result, negativeSuffix, delegate,
618 getNegativeSuffixFieldPositions(), Field.SIGN);
619 } else {
620 append(result, positiveSuffix, delegate,
621 getPositiveSuffixFieldPositions(), Field.SIGN);
622 }
623
624 return result;
625 }
626
627 if (isNegative) {
628 number = -number;
629 }
630
631 // at this point we are guaranteed a nonnegative finite number.
632 assert(number >= 0 && !Double.isInfinite(number));
633
634 synchronized(digitList) {
635 int maxIntDigits = super.getMaximumIntegerDigits();
636 int minIntDigits = super.getMinimumIntegerDigits();
637 int maxFraDigits = super.getMaximumFractionDigits();
638 int minFraDigits = super.getMinimumFractionDigits();
639
640 digitList.set(isNegative, number, useExponentialNotation ?
641 maxIntDigits + maxFraDigits : maxFraDigits,
642 !useExponentialNotation);
643 return subformat(result, delegate, isNegative, false,
644 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
645 }
646 }
647
648 /**
649 * Format a long to produce a string.
650 * @param number The long to format
651 * @param result where the text is to be appended
652 * @param fieldPosition keeps track on the position of the field within
653 * the returned string. For example, for formatting
654 * a number {@code 123456789} in {@code Locale.US}
655 * locale, if the given {@code fieldPosition} is
656 * {@link NumberFormat#INTEGER_FIELD}, the begin index
657 * and end index of {@code fieldPosition} will be set
658 * to 0 and 11, respectively for the output string
659 * {@code 123,456,789}.
660 * @exception NullPointerException if {@code result} or
661 * {@code fieldPosition} is {@code null}
666 */
667 @Override
668 public StringBuffer format(long number, StringBuffer result,
669 FieldPosition fieldPosition) {
670 fieldPosition.setBeginIndex(0);
671 fieldPosition.setEndIndex(0);
672
673 return format(number, result, fieldPosition.getFieldDelegate());
674 }
675
676 /**
677 * Format a long to produce a string.
678 * @param number The long to format
679 * @param result where the text is to be appended
680 * @param delegate notified of locations of sub fields
681 * @return The formatted number string
682 * @exception ArithmeticException if rounding is needed with rounding
683 * mode being set to RoundingMode.UNNECESSARY
684 * @see java.text.FieldPosition
685 */
686 private StringBuffer format(long number, StringBuffer result,
687 FieldDelegate delegate) {
688 boolean isNegative = (number < 0);
689 if (isNegative) {
690 number = -number;
691 }
692
693 // In general, long values always represent real finite numbers, so
694 // we don't have to check for +/- Infinity or NaN. However, there
695 // is one case we have to be careful of: The multiplier can push
696 // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
697 // check for this before multiplying, and if it happens we use
698 // BigInteger instead.
699 boolean useBigInteger = false;
700 if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
701 if (multiplier != 0) {
702 useBigInteger = true;
703 }
704 } else if (multiplier != 1 && multiplier != 0) {
705 long cutoff = Long.MAX_VALUE / multiplier;
706 if (cutoff < 0) {
757 * @exception ArithmeticException if rounding is needed with rounding
758 * mode being set to RoundingMode.UNNECESSARY
759 * @see java.text.FieldPosition
760 */
761 private StringBuffer format(BigDecimal number, StringBuffer result,
762 FieldPosition fieldPosition) {
763 fieldPosition.setBeginIndex(0);
764 fieldPosition.setEndIndex(0);
765 return format(number, result, fieldPosition.getFieldDelegate());
766 }
767
768 /**
769 * Formats a BigDecimal to produce a string.
770 * @param number The BigDecimal to format
771 * @param result where the text is to be appended
772 * @param delegate notified of locations of sub fields
773 * @exception ArithmeticException if rounding is needed with rounding
774 * mode being set to RoundingMode.UNNECESSARY
775 * @return The formatted number string
776 */
777 private StringBuffer format(BigDecimal number, StringBuffer result,
778 FieldDelegate delegate) {
779 if (multiplier != 1) {
780 number = number.multiply(getBigDecimalMultiplier());
781 }
782 boolean isNegative = number.signum() == -1;
783 if (isNegative) {
784 number = number.negate();
785 }
786
787 synchronized(digitList) {
788 int maxIntDigits = getMaximumIntegerDigits();
789 int minIntDigits = getMinimumIntegerDigits();
790 int maxFraDigits = getMaximumFractionDigits();
791 int minFraDigits = getMinimumFractionDigits();
792 int maximumDigits = maxIntDigits + maxFraDigits;
793
794 digitList.set(isNegative, number, useExponentialNotation ?
795 ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
796 maxFraDigits, !useExponentialNotation);
797
818 * @see java.text.FieldPosition
819 */
820 private StringBuffer format(BigInteger number, StringBuffer result,
821 FieldPosition fieldPosition) {
822 fieldPosition.setBeginIndex(0);
823 fieldPosition.setEndIndex(0);
824
825 return format(number, result, fieldPosition.getFieldDelegate(), false);
826 }
827
828 /**
829 * Format a BigInteger to produce a string.
830 * @param number The BigInteger to format
831 * @param result where the text is to be appended
832 * @param delegate notified of locations of sub fields
833 * @return The formatted number string
834 * @exception ArithmeticException if rounding is needed with rounding
835 * mode being set to RoundingMode.UNNECESSARY
836 * @see java.text.FieldPosition
837 */
838 private StringBuffer format(BigInteger number, StringBuffer result,
839 FieldDelegate delegate, boolean formatLong) {
840 if (multiplier != 1) {
841 number = number.multiply(getBigIntegerMultiplier());
842 }
843 boolean isNegative = number.signum() == -1;
844 if (isNegative) {
845 number = number.negate();
846 }
847
848 synchronized(digitList) {
849 int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
850 if (formatLong) {
851 maxIntDigits = super.getMaximumIntegerDigits();
852 minIntDigits = super.getMinimumIntegerDigits();
853 maxFraDigits = super.getMaximumFractionDigits();
854 minFraDigits = super.getMinimumFractionDigits();
855 maximumDigits = maxIntDigits + maxFraDigits;
856 } else {
857 maxIntDigits = getMaximumIntegerDigits();
858 minIntDigits = getMinimumIntegerDigits();
900 if (obj instanceof Double || obj instanceof Float) {
901 format(((Number)obj).doubleValue(), sb, delegate);
902 } else if (obj instanceof Long || obj instanceof Integer ||
903 obj instanceof Short || obj instanceof Byte ||
904 obj instanceof AtomicInteger || obj instanceof AtomicLong) {
905 format(((Number)obj).longValue(), sb, delegate);
906 } else if (obj instanceof BigDecimal) {
907 format((BigDecimal)obj, sb, delegate);
908 } else if (obj instanceof BigInteger) {
909 format((BigInteger)obj, sb, delegate, false);
910 } else if (obj == null) {
911 throw new NullPointerException(
912 "formatToCharacterIterator must be passed non-null object");
913 } else {
914 throw new IllegalArgumentException(
915 "Cannot format given Object as a Number");
916 }
917 return delegate.getIterator(sb.toString());
918 }
919
920 // ==== Begin fast-path formating logic for double =========================
921
922 /* Fast-path formatting will be used for format(double ...) methods iff a
923 * number of conditions are met (see checkAndSetFastPathStatus()):
924 * - Only if instance properties meet the right predefined conditions.
925 * - The abs value of the double to format is <= Integer.MAX_VALUE.
926 *
927 * The basic approach is to split the binary to decimal conversion of a
928 * double value into two phases:
929 * * The conversion of the integer portion of the double.
930 * * The conversion of the fractional portion of the double
931 * (limited to two or three digits).
932 *
933 * The isolation and conversion of the integer portion of the double is
934 * straightforward. The conversion of the fraction is more subtle and relies
935 * on some rounding properties of double to the decimal precisions in
936 * question. Using the terminology of BigDecimal, this fast-path algorithm
937 * is applied when a double value has a magnitude less than Integer.MAX_VALUE
938 * and rounding is to nearest even and the destination format has two or
939 * three digits of *scale* (digits after the decimal point).
940 *
1645 /*
1646 * If the fast path data is not set through
1647 * checkAndSetFastPathStatus() and fulfil the
1648 * fast path conditions then reset the data
1649 * directly through resetFastPathData()
1650 */
1651 resetFastPathData(isFastPath);
1652 }
1653 fastDoubleFormat(d, negative);
1654
1655 }
1656
1657
1658 // Returns a new string from updated fastPathContainer.
1659 return new String(fastPathData.fastPathContainer,
1660 fastPathData.firstUsedIndex,
1661 fastPathData.lastFreeIndex - fastPathData.firstUsedIndex);
1662
1663 }
1664
1665 // ======== End fast-path formating logic for double =========================
1666
1667 /**
1668 * Complete the formatting of a finite number. On entry, the digitList must
1669 * be filled in with the correct digits.
1670 */
1671 private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
1672 boolean isNegative, boolean isInteger,
1673 int maxIntDigits, int minIntDigits,
1674 int maxFraDigits, int minFraDigits) {
1675 // NOTE: This isn't required anymore because DigitList takes care of this.
1676 //
1677 // // The negative of the exponent represents the number of leading
1678 // // zeros between the decimal and the first non-zero digit, for
1679 // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
1680 // // is more than the maximum fraction digits, then we have an underflow
1681 // // for the printed representation. We recognize this here and set
1682 // // the DigitList representation to zero in this situation.
1683 //
1684 // if (-digitList.decimalAt >= getMaximumFractionDigits())
1685 // {
1686 // digitList.count = 0;
1687 // }
1688
1689 char zero = symbols.getZeroDigit();
1690 int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
1691 char grouping = symbols.getGroupingSeparator();
1692 char decimal = isCurrencyFormat ?
1693 symbols.getMonetaryDecimalSeparator() :
1694 symbols.getDecimalSeparator();
1695
1696 /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
1697 * format as zero. This allows sensible computations and preserves
1698 * relations such as signum(1/x) = signum(x), where x is +Infinity or
1699 * -Infinity. Prior to this fix, we always formatted zero values as if
1700 * they were positive. Liu 7/6/98.
1701 */
1702 if (digitList.isZero()) {
1703 digitList.decimalAt = 0; // Normalize
1704 }
1705
1706 if (isNegative) {
1707 append(result, negativePrefix, delegate,
1708 getNegativePrefixFieldPositions(), Field.SIGN);
1709 } else {
1710 append(result, positivePrefix, delegate,
1711 getPositivePrefixFieldPositions(), Field.SIGN);
1712 }
1713
1714 if (useExponentialNotation) {
1715 int iFieldStart = result.length();
1716 int iFieldEnd = -1;
1717 int fFieldStart = -1;
1718
1719 // Minimum integer digits are handled in exponential format by
1720 // adjusting the exponent. For example, 0.01234 with 3 minimum
1721 // integer digits is "123.4E-4".
1722
1723 // Maximum integer digits are interpreted as indicating the
1724 // repeating range. This is useful for engineering notation, in
1725 // which the exponent is restricted to a multiple of 3. For
1726 // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
1727 // If maximum integer digits are > 1 and are larger than
1728 // minimum integer digits, then minimum integer digits are
1729 // ignored.
1730 int exponent = digitList.decimalAt;
1731 int repeat = maxIntDigits;
1732 int minimumIntegerDigits = minIntDigits;
1733 if (repeat > 1 && repeat > minIntDigits) {
1734 // A repeating range is defined; adjust to it as follows.
1735 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
1736 // -3,-4,-5=>-6, etc. This takes into account that the
1737 // exponent we have here is off by one from what we expect;
1738 // it is for the format 0.MMMMMx10^n.
1739 if (exponent >= 1) {
1740 exponent = ((exponent - 1) / repeat) * repeat;
1741 } else {
1742 // integer division rounds towards 0
1942 // after the decimal but before any significant digits. These
1943 // are only output if abs(number being formatted) < 1.0.
1944 if (-1-i > (digitList.decimalAt-1)) {
1945 result.append(zero);
1946 continue;
1947 }
1948
1949 // Output a digit, if we have any precision left, or a
1950 // zero if we don't. We don't want to output noise digits.
1951 if (!isInteger && digitIndex < digitList.count) {
1952 result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
1953 } else {
1954 result.append(zero);
1955 }
1956 }
1957
1958 // Record field information for caller.
1959 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
1960 fFieldStart, result.length(), result);
1961 }
1962
1963 if (isNegative) {
1964 append(result, negativeSuffix, delegate,
1965 getNegativeSuffixFieldPositions(), Field.SIGN);
1966 } else {
1967 append(result, positiveSuffix, delegate,
1968 getPositiveSuffixFieldPositions(), Field.SIGN);
1969 }
1970
1971 return result;
1972 }
1973
1974 /**
1975 * Appends the String <code>string</code> to <code>result</code>.
1976 * <code>delegate</code> is notified of all the
1977 * <code>FieldPosition</code>s in <code>positions</code>.
1978 * <p>
1979 * If one of the <code>FieldPosition</code>s in <code>positions</code>
1980 * identifies a <code>SIGN</code> attribute, it is mapped to
1981 * <code>signAttribute</code>. This is used
1982 * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
1983 * attribute as necessary.
1984 * <p>
1985 * This is used by <code>subformat</code> to add the prefix/suffix.
1986 */
1987 private void append(StringBuffer result, String string,
1988 FieldDelegate delegate,
1989 FieldPosition[] positions,
1990 Format.Field signAttribute) {
1991 int start = result.length();
2197 private static final int STATUS_LENGTH = 2;
2198
2199 /**
2200 * Parse the given text into a number. The text is parsed beginning at
2201 * parsePosition, until an unparseable character is seen.
2202 * @param text The string to parse.
2203 * @param parsePosition The position at which to being parsing. Upon
2204 * return, the first unparseable character.
2205 * @param digits The DigitList to set to the parsed value.
2206 * @param isExponent If true, parse an exponent. This means no
2207 * infinite values and integer only.
2208 * @param status Upon return contains boolean status flags indicating
2209 * whether the value was infinite and whether it was positive.
2210 */
2211 private final boolean subparse(String text, ParsePosition parsePosition,
2212 String positivePrefix, String negativePrefix,
2213 DigitList digits, boolean isExponent,
2214 boolean status[]) {
2215 int position = parsePosition.index;
2216 int oldStart = parsePosition.index;
2217 int backup;
2218 boolean gotPositive, gotNegative;
2219
2220 // check for positivePrefix; take longest
2221 gotPositive = text.regionMatches(position, positivePrefix, 0,
2222 positivePrefix.length());
2223 gotNegative = text.regionMatches(position, negativePrefix, 0,
2224 negativePrefix.length());
2225
2226 if (gotPositive && gotNegative) {
2227 if (positivePrefix.length() > negativePrefix.length()) {
2228 gotNegative = false;
2229 } else if (positivePrefix.length() < negativePrefix.length()) {
2230 gotPositive = false;
2231 }
2232 }
2233
2234 if (gotPositive) {
2235 position += positivePrefix.length();
2236 } else if (gotNegative) {
2237 position += negativePrefix.length();
2238 } else {
2239 parsePosition.errorIndex = position;
2240 return false;
2241 }
2242
2243 // process digits or Inf, find decimal position
2244 status[STATUS_INFINITE] = false;
2245 if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
2246 symbols.getInfinity().length())) {
2247 position += symbols.getInfinity().length();
2248 status[STATUS_INFINITE] = true;
2249 } else {
2250 // We now have a string of digits, possibly with grouping symbols,
2251 // and decimal points. We want to process these into a DigitList.
2252 // We don't want to put a bunch of leading zeros into the DigitList
2253 // though, so we keep track of the location of the decimal point,
2254 // put only significant digits into the DigitList, and adjust the
2255 // exponent as needed.
2256
2257 digits.decimalAt = digits.count = 0;
2258 char zero = symbols.getZeroDigit();
2259 char decimal = isCurrencyFormat ?
2260 symbols.getMonetaryDecimalSeparator() :
2261 symbols.getDecimalSeparator();
2262 char grouping = symbols.getGroupingSeparator();
2263 String exponentString = symbols.getExponentSeparator();
2264 boolean sawDecimal = false;
2265 boolean sawExponent = false;
2266 boolean sawDigit = false;
2267 int exponent = 0; // Set to the exponent value, if any
2268
2269 // We have to track digitCount ourselves, because digits.count will
2270 // pin when the maximum allowable digits is reached.
2271 int digitCount = 0;
2272
2273 backup = -1;
2274 for (; position < text.length(); ++position) {
2275 char ch = text.charAt(position);
2276
2277 /* We recognize all digit ranges, not only the Latin digit range
2278 * '0'..'9'. We do so by using the Character.digit() method,
2279 * which converts a valid Unicode digit to the range 0..9.
2280 *
2281 * The character 'ch' may be a digit. If so, place its value
2282 * from 0 to 9 in 'digit'. First try using the locale digit,
2283 * which may or MAY NOT be a standard Unicode digit range. If
2284 * this fails, try using the standard Unicode digit ranges by
2285 * calling Character.digit(). If this also fails, digit will
2286 * have a value outside the range 0..9.
2287 */
2288 int digit = ch - zero;
2289 if (digit < 0 || digit > 9) {
2290 digit = Character.digit(ch, 10);
2291 }
2292
2293 if (digit == 0) {
2317 digits.append((char)(digit + '0'));
2318
2319 // Cancel out backup setting (see grouping handler below)
2320 backup = -1;
2321 } else if (!isExponent && ch == decimal) {
2322 // If we're only parsing integers, or if we ALREADY saw the
2323 // decimal, then don't parse this one.
2324 if (isParseIntegerOnly() || sawDecimal) {
2325 break;
2326 }
2327 digits.decimalAt = digitCount; // Not digits.count!
2328 sawDecimal = true;
2329 } else if (!isExponent && ch == grouping && isGroupingUsed()) {
2330 if (sawDecimal) {
2331 break;
2332 }
2333 // Ignore grouping characters, if we are using them, but
2334 // require that they be followed by a digit. Otherwise
2335 // we backup and reprocess them.
2336 backup = position;
2337 } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
2338 && !sawExponent) {
2339 // Process the exponent by recursively calling this method.
2340 ParsePosition pos = new ParsePosition(position + exponentString.length());
2341 boolean[] stat = new boolean[STATUS_LENGTH];
2342 DigitList exponentDigits = new DigitList();
2343
2344 if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
2345 exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
2346 position = pos.index; // Advance past the exponent
2347 exponent = (int)exponentDigits.getLong();
2348 if (!stat[STATUS_POSITIVE]) {
2349 exponent = -exponent;
2350 }
2351 sawExponent = true;
2352 }
2353 break; // Whether we fail or succeed, we exit this loop
2354 } else {
2355 break;
2356 }
2357 }
2358
2359 if (backup != -1) {
2360 position = backup;
2361 }
2362
2363 // If there was no decimal point we have an integer
2364 if (!sawDecimal) {
2365 digits.decimalAt = digitCount; // Not digits.count!
2366 }
2367
2368 // Adjust for exponent, if any
2369 digits.decimalAt += exponent;
2370
2371 // If none of the text string was recognized. For example, parse
2372 // "x" with pattern "#0.00" (return index and error index both 0)
2373 // parse "$" with pattern "$#0.00". (return index 0 and error
2374 // index 1).
2375 if (!sawDigit && digitCount == 0) {
2376 parsePosition.index = oldStart;
2377 parsePosition.errorIndex = oldStart;
2378 return false;
2379 }
2380 }
2381
2382 // check for suffix
2383 if (!isExponent) {
2384 if (gotPositive) {
2385 gotPositive = text.regionMatches(position,positiveSuffix,0,
2386 positiveSuffix.length());
2387 }
2388 if (gotNegative) {
2389 gotNegative = text.regionMatches(position,negativeSuffix,0,
2390 negativeSuffix.length());
2391 }
2392
2393 // if both match, take longest
2394 if (gotPositive && gotNegative) {
2395 if (positiveSuffix.length() > negativeSuffix.length()) {
2396 gotNegative = false;
2397 } else if (positiveSuffix.length() < negativeSuffix.length()) {
2398 gotPositive = false;
2399 }
2400 }
2401
2402 // fail if neither or both
2403 if (gotPositive == gotNegative) {
2404 parsePosition.errorIndex = position;
2405 return false;
2406 }
2407
2408 parsePosition.index = position +
2409 (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
2410 } else {
2411 parsePosition.index = position;
2412 }
2413
2414 status[STATUS_POSITIVE] = gotPositive;
2415 if (parsePosition.index == oldStart) {
2416 parsePosition.errorIndex = position;
2417 return false;
2418 }
2419 return true;
2420 }
2421
2422 /**
2423 * Returns a copy of the decimal format symbols, which is generally not
2424 * changed by the programmer or user.
2425 * @return a copy of the desired DecimalFormatSymbols
2426 * @see java.text.DecimalFormatSymbols
2427 */
2428 public DecimalFormatSymbols getDecimalFormatSymbols() {
2429 try {
2430 // don't allow multiple references
2431 return (DecimalFormatSymbols) symbols.clone();
2432 } catch (Exception foo) {
2433 return null; // should never happen
2434 }
2435 }
2436
2437
2438 /**
2439 * Sets the decimal format symbols, which is generally not changed
|
1 /*
2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 * materials are provided under terms of a License Agreement between Taligent
33 * and Sun. This technology is protected by multiple US and International
34 * patents. This notice and attribution to Taligent may not be removed.
35 * Taligent is a registered trademark of Taligent, Inc.
36 *
37 */
38
39 package java.text;
40
41 import java.io.IOException;
42 import java.io.InvalidObjectException;
43 import java.io.ObjectInputStream;
44 import java.math.BigDecimal;
45 import java.math.BigInteger;
46 import java.math.RoundingMode;
47 import java.text.spi.NumberFormatProvider;
48 import java.util.ArrayList;
49 import java.util.Currency;
50 import java.util.Locale;
51 import java.util.concurrent.atomic.AtomicInteger;
52 import java.util.concurrent.atomic.AtomicLong;
53 import sun.util.locale.provider.LocaleProviderAdapter;
54 import sun.util.locale.provider.ResourceBundleBasedAdapter;
55
56 /**
57 * <code>DecimalFormat</code> is a concrete subclass of
58 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
59 * features designed to make it possible to parse and format numbers in any
60 * locale, including support for Western, Arabic, and Indic digits. It also
61 * supports different kinds of numbers, including integers (123), fixed-point
62 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
63 * currency amounts ($123). All of these can be localized.
64 *
65 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
66 * default locale, call one of <code>NumberFormat</code>'s factory methods, such
67 * as <code>getInstance()</code>. In general, do not call the
68 * <code>DecimalFormat</code> constructors directly, since the
69 * <code>NumberFormat</code> factory methods may return subclasses other than
70 * <code>DecimalFormat</code>. If you need to customize the format object, do
137 *
138 * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
139 * thousands separators, decimal separators, etc. may be set to arbitrary
140 * values, and they will appear properly during formatting. However, care must
141 * be taken that the symbols and strings do not conflict, or parsing will be
142 * unreliable. For example, either the positive and negative prefixes or the
143 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
144 * to distinguish positive from negative values. (If they are identical, then
145 * <code>DecimalFormat</code> will behave as if no negative subpattern was
146 * specified.) Another example is that the decimal separator and thousands
147 * separator should be distinct characters, or parsing will be impossible.
148 *
149 * <p>The grouping separator is commonly used for thousands, but in some
150 * countries it separates ten-thousands. The grouping size is a constant number
151 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
152 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
153 * interval between the last one and the end of the integer is the one that is
154 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
155 * <code>"##,####,####"</code>.
156 *
157 * <h4><a id="special_pattern_character">Special Pattern Characters</a></h4>
158 *
159 * <p>Many characters in a pattern are taken literally; they are matched during
160 * parsing and output unchanged during formatting. Special characters, on the
161 * other hand, stand for other characters, strings, or classes of characters.
162 * They must be quoted, unless noted otherwise, if they are to appear in the
163 * prefix or suffix as literals.
164 *
165 * <p>The characters listed here are used in non-localized patterns. Localized
166 * patterns use the corresponding characters taken from this formatter's
167 * <code>DecimalFormatSymbols</code> object instead, and these characters lose
168 * their special status. Two exceptions are the currency sign and quote, which
169 * are not localized.
170 *
171 * <blockquote>
172 * <table class="striped">
173 * <caption style="display:none">Chart showing symbol, location, localized, and meaning.</caption>
174 * <thead>
175 * <tr>
176 * <th scope="col" style="text-align:left">Symbol
177 * <th scope="col" style="text-align:left">Location
552 String tempResult = fastFormat(number);
553 if (tempResult != null) {
554 result.append(tempResult);
555 return result;
556 }
557 }
558
559 // if fast-path could not work, we fallback to standard code.
560 return format(number, result, fieldPosition.getFieldDelegate());
561 }
562
563 /**
564 * Formats a double to produce a string.
565 * @param number The double to format
566 * @param result where the text is to be appended
567 * @param delegate notified of locations of sub fields
568 * @exception ArithmeticException if rounding is needed with rounding
569 * mode being set to RoundingMode.UNNECESSARY
570 * @return The formatted number string
571 */
572 StringBuffer format(double number, StringBuffer result,
573 FieldDelegate delegate) {
574
575 boolean nanOrInfinity = handleNaN(number, result, delegate);
576 if (nanOrInfinity) {
577 return result;
578 }
579
580 /* Detecting whether a double is negative is easy with the exception of
581 * the value -0.0. This is a double which has a zero mantissa (and
582 * exponent), but a negative sign bit. It is semantically distinct from
583 * a zero with a positive sign bit, and this distinction is important
584 * to certain kinds of computations. However, it's a little tricky to
585 * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
586 * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
587 * -Infinity. Proper detection of -0.0 is needed to deal with the
588 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
589 */
590 boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
591
592 if (multiplier != 1) {
593 number *= multiplier;
594 }
595
596 nanOrInfinity = handleInfinity(number, result, delegate, isNegative);
597 if (nanOrInfinity) {
598 return result;
599 }
600
601 if (isNegative) {
602 number = -number;
603 }
604
605 // at this point we are guaranteed a nonnegative finite number.
606 assert (number >= 0 && !Double.isInfinite(number));
607 return doubleSubformat(number, result, delegate, isNegative);
608 }
609
610 /**
611 * Checks if the given {@code number} is {@code Double.NaN}. if yes;
612 * appends the NaN symbol to the result string. The NaN string is
613 * determined by the DecimalFormatSymbols object.
614 * @param number the double number to format
615 * @param result where the text is to be appended
616 * @param delegate notified of locations of sub fields
617 * @return true, if number is a NaN; false otherwise
618 */
619 boolean handleNaN(double number, StringBuffer result,
620 FieldDelegate delegate) {
621 if (Double.isNaN(number)
622 || (Double.isInfinite(number) && multiplier == 0)) {
623 int iFieldStart = result.length();
624 result.append(symbols.getNaN());
625 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
626 iFieldStart, result.length(), result);
627 return true;
628 }
629 return false;
630 }
631
632 /**
633 * Checks if the given {@code number} is {@code Double.NEGATIVE_INFINITY}
634 * or {@code Double.POSITIVE_INFINITY}. if yes;
635 * appends the infinity string to the result string. The infinity string is
636 * determined by the DecimalFormatSymbols object.
637 * @param number the double number to format
638 * @param result where the text is to be appended
639 * @param delegate notified of locations of sub fields
640 * @param isNegative whether the given {@code number} is negative
641 * @return true, if number is a {@code Double.NEGATIVE_INFINITY} or
642 * {@code Double.POSITIVE_INFINITY}; false otherwise
643 */
644 boolean handleInfinity(double number, StringBuffer result,
645 FieldDelegate delegate, boolean isNegative) {
646 if (Double.isInfinite(number)) {
647 if (isNegative) {
648 append(result, negativePrefix, delegate,
649 getNegativePrefixFieldPositions(), Field.SIGN);
650 } else {
651 append(result, positivePrefix, delegate,
652 getPositivePrefixFieldPositions(), Field.SIGN);
653 }
654
655 int iFieldStart = result.length();
656 result.append(symbols.getInfinity());
657 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
658 iFieldStart, result.length(), result);
659
660 if (isNegative) {
661 append(result, negativeSuffix, delegate,
662 getNegativeSuffixFieldPositions(), Field.SIGN);
663 } else {
664 append(result, positiveSuffix, delegate,
665 getPositiveSuffixFieldPositions(), Field.SIGN);
666 }
667
668 return true;
669 }
670 return false;
671 }
672
673 StringBuffer doubleSubformat(double number, StringBuffer result,
674 FieldDelegate delegate, boolean isNegative) {
675 synchronized (digitList) {
676 int maxIntDigits = super.getMaximumIntegerDigits();
677 int minIntDigits = super.getMinimumIntegerDigits();
678 int maxFraDigits = super.getMaximumFractionDigits();
679 int minFraDigits = super.getMinimumFractionDigits();
680
681 digitList.set(isNegative, number, useExponentialNotation
682 ? maxIntDigits + maxFraDigits : maxFraDigits,
683 !useExponentialNotation);
684 return subformat(result, delegate, isNegative, false,
685 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
686 }
687 }
688
689 /**
690 * Format a long to produce a string.
691 * @param number The long to format
692 * @param result where the text is to be appended
693 * @param fieldPosition keeps track on the position of the field within
694 * the returned string. For example, for formatting
695 * a number {@code 123456789} in {@code Locale.US}
696 * locale, if the given {@code fieldPosition} is
697 * {@link NumberFormat#INTEGER_FIELD}, the begin index
698 * and end index of {@code fieldPosition} will be set
699 * to 0 and 11, respectively for the output string
700 * {@code 123,456,789}.
701 * @exception NullPointerException if {@code result} or
702 * {@code fieldPosition} is {@code null}
707 */
708 @Override
709 public StringBuffer format(long number, StringBuffer result,
710 FieldPosition fieldPosition) {
711 fieldPosition.setBeginIndex(0);
712 fieldPosition.setEndIndex(0);
713
714 return format(number, result, fieldPosition.getFieldDelegate());
715 }
716
717 /**
718 * Format a long to produce a string.
719 * @param number The long to format
720 * @param result where the text is to be appended
721 * @param delegate notified of locations of sub fields
722 * @return The formatted number string
723 * @exception ArithmeticException if rounding is needed with rounding
724 * mode being set to RoundingMode.UNNECESSARY
725 * @see java.text.FieldPosition
726 */
727 StringBuffer format(long number, StringBuffer result,
728 FieldDelegate delegate) {
729 boolean isNegative = (number < 0);
730 if (isNegative) {
731 number = -number;
732 }
733
734 // In general, long values always represent real finite numbers, so
735 // we don't have to check for +/- Infinity or NaN. However, there
736 // is one case we have to be careful of: The multiplier can push
737 // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
738 // check for this before multiplying, and if it happens we use
739 // BigInteger instead.
740 boolean useBigInteger = false;
741 if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
742 if (multiplier != 0) {
743 useBigInteger = true;
744 }
745 } else if (multiplier != 1 && multiplier != 0) {
746 long cutoff = Long.MAX_VALUE / multiplier;
747 if (cutoff < 0) {
798 * @exception ArithmeticException if rounding is needed with rounding
799 * mode being set to RoundingMode.UNNECESSARY
800 * @see java.text.FieldPosition
801 */
802 private StringBuffer format(BigDecimal number, StringBuffer result,
803 FieldPosition fieldPosition) {
804 fieldPosition.setBeginIndex(0);
805 fieldPosition.setEndIndex(0);
806 return format(number, result, fieldPosition.getFieldDelegate());
807 }
808
809 /**
810 * Formats a BigDecimal to produce a string.
811 * @param number The BigDecimal to format
812 * @param result where the text is to be appended
813 * @param delegate notified of locations of sub fields
814 * @exception ArithmeticException if rounding is needed with rounding
815 * mode being set to RoundingMode.UNNECESSARY
816 * @return The formatted number string
817 */
818 StringBuffer format(BigDecimal number, StringBuffer result,
819 FieldDelegate delegate) {
820 if (multiplier != 1) {
821 number = number.multiply(getBigDecimalMultiplier());
822 }
823 boolean isNegative = number.signum() == -1;
824 if (isNegative) {
825 number = number.negate();
826 }
827
828 synchronized(digitList) {
829 int maxIntDigits = getMaximumIntegerDigits();
830 int minIntDigits = getMinimumIntegerDigits();
831 int maxFraDigits = getMaximumFractionDigits();
832 int minFraDigits = getMinimumFractionDigits();
833 int maximumDigits = maxIntDigits + maxFraDigits;
834
835 digitList.set(isNegative, number, useExponentialNotation ?
836 ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
837 maxFraDigits, !useExponentialNotation);
838
859 * @see java.text.FieldPosition
860 */
861 private StringBuffer format(BigInteger number, StringBuffer result,
862 FieldPosition fieldPosition) {
863 fieldPosition.setBeginIndex(0);
864 fieldPosition.setEndIndex(0);
865
866 return format(number, result, fieldPosition.getFieldDelegate(), false);
867 }
868
869 /**
870 * Format a BigInteger to produce a string.
871 * @param number The BigInteger to format
872 * @param result where the text is to be appended
873 * @param delegate notified of locations of sub fields
874 * @return The formatted number string
875 * @exception ArithmeticException if rounding is needed with rounding
876 * mode being set to RoundingMode.UNNECESSARY
877 * @see java.text.FieldPosition
878 */
879 StringBuffer format(BigInteger number, StringBuffer result,
880 FieldDelegate delegate, boolean formatLong) {
881 if (multiplier != 1) {
882 number = number.multiply(getBigIntegerMultiplier());
883 }
884 boolean isNegative = number.signum() == -1;
885 if (isNegative) {
886 number = number.negate();
887 }
888
889 synchronized(digitList) {
890 int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
891 if (formatLong) {
892 maxIntDigits = super.getMaximumIntegerDigits();
893 minIntDigits = super.getMinimumIntegerDigits();
894 maxFraDigits = super.getMaximumFractionDigits();
895 minFraDigits = super.getMinimumFractionDigits();
896 maximumDigits = maxIntDigits + maxFraDigits;
897 } else {
898 maxIntDigits = getMaximumIntegerDigits();
899 minIntDigits = getMinimumIntegerDigits();
941 if (obj instanceof Double || obj instanceof Float) {
942 format(((Number)obj).doubleValue(), sb, delegate);
943 } else if (obj instanceof Long || obj instanceof Integer ||
944 obj instanceof Short || obj instanceof Byte ||
945 obj instanceof AtomicInteger || obj instanceof AtomicLong) {
946 format(((Number)obj).longValue(), sb, delegate);
947 } else if (obj instanceof BigDecimal) {
948 format((BigDecimal)obj, sb, delegate);
949 } else if (obj instanceof BigInteger) {
950 format((BigInteger)obj, sb, delegate, false);
951 } else if (obj == null) {
952 throw new NullPointerException(
953 "formatToCharacterIterator must be passed non-null object");
954 } else {
955 throw new IllegalArgumentException(
956 "Cannot format given Object as a Number");
957 }
958 return delegate.getIterator(sb.toString());
959 }
960
961 // ==== Begin fast-path formatting logic for double =========================
962
963 /* Fast-path formatting will be used for format(double ...) methods iff a
964 * number of conditions are met (see checkAndSetFastPathStatus()):
965 * - Only if instance properties meet the right predefined conditions.
966 * - The abs value of the double to format is <= Integer.MAX_VALUE.
967 *
968 * The basic approach is to split the binary to decimal conversion of a
969 * double value into two phases:
970 * * The conversion of the integer portion of the double.
971 * * The conversion of the fractional portion of the double
972 * (limited to two or three digits).
973 *
974 * The isolation and conversion of the integer portion of the double is
975 * straightforward. The conversion of the fraction is more subtle and relies
976 * on some rounding properties of double to the decimal precisions in
977 * question. Using the terminology of BigDecimal, this fast-path algorithm
978 * is applied when a double value has a magnitude less than Integer.MAX_VALUE
979 * and rounding is to nearest even and the destination format has two or
980 * three digits of *scale* (digits after the decimal point).
981 *
1686 /*
1687 * If the fast path data is not set through
1688 * checkAndSetFastPathStatus() and fulfil the
1689 * fast path conditions then reset the data
1690 * directly through resetFastPathData()
1691 */
1692 resetFastPathData(isFastPath);
1693 }
1694 fastDoubleFormat(d, negative);
1695
1696 }
1697
1698
1699 // Returns a new string from updated fastPathContainer.
1700 return new String(fastPathData.fastPathContainer,
1701 fastPathData.firstUsedIndex,
1702 fastPathData.lastFreeIndex - fastPathData.firstUsedIndex);
1703
1704 }
1705
1706 /**
1707 * Sets the {@code DigitList} used by this {@code DecimalFormat}
1708 * instance.
1709 * @param number the number to format
1710 * @param isNegative true, if the number is negative; false otherwise
1711 * @param maxDigits the max digits
1712 */
1713 void setDigitList(Number number, boolean isNegative, int maxDigits) {
1714
1715 if (number instanceof Double) {
1716 digitList.set(isNegative, (Double) number, maxDigits, true);
1717 } else if (number instanceof BigDecimal) {
1718 digitList.set(isNegative, (BigDecimal) number, maxDigits, true);
1719 } else if (number instanceof Long) {
1720 digitList.set(isNegative, (Long) number, maxDigits);
1721 } else if (number instanceof BigInteger) {
1722 digitList.set(isNegative, (BigInteger) number, maxDigits);
1723 }
1724 }
1725
1726 // ======== End fast-path formating logic for double =========================
1727
1728 /**
1729 * Complete the formatting of a finite number. On entry, the digitList must
1730 * be filled in with the correct digits.
1731 */
1732 private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
1733 boolean isNegative, boolean isInteger,
1734 int maxIntDigits, int minIntDigits,
1735 int maxFraDigits, int minFraDigits) {
1736
1737 // process prefix
1738 if (isNegative) {
1739 append(result, negativePrefix, delegate,
1740 getNegativePrefixFieldPositions(), Field.SIGN);
1741 } else {
1742 append(result, positivePrefix, delegate,
1743 getPositivePrefixFieldPositions(), Field.SIGN);
1744 }
1745
1746 // process number
1747 subformatNumber(result, delegate, isNegative, isInteger,
1748 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
1749
1750 // process suffix
1751 if (isNegative) {
1752 append(result, negativeSuffix, delegate,
1753 getNegativeSuffixFieldPositions(), Field.SIGN);
1754 } else {
1755 append(result, positiveSuffix, delegate,
1756 getPositiveSuffixFieldPositions(), Field.SIGN);
1757 }
1758
1759 return result;
1760 }
1761
1762 /**
1763 * Subformats number part using the {@code DigitList} of this
1764 * {@code DecimalFormat} instance.
1765 * @param result where the text is to be appended
1766 * @param delegate notified of the location of sub fields
1767 * @param isNegative true, if the number is negative; false otherwise
1768 * @param isInteger true, if the number is an integer; false otherwise
1769 * @param maxIntDigits maximum integer digits
1770 * @param minIntDigits minimum integer digits
1771 * @param maxFraDigits maximum fraction digits
1772 * @param minFraDigits minimum fraction digits
1773 */
1774 void subformatNumber(StringBuffer result, FieldDelegate delegate,
1775 boolean isNegative, boolean isInteger,
1776 int maxIntDigits, int minIntDigits,
1777 int maxFraDigits, int minFraDigits) {
1778
1779 char grouping = symbols.getGroupingSeparator();
1780 char zero = symbols.getZeroDigit();
1781 int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
1782
1783 char decimal = isCurrencyFormat ?
1784 symbols.getMonetaryDecimalSeparator() :
1785 symbols.getDecimalSeparator();
1786
1787 /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
1788 * format as zero. This allows sensible computations and preserves
1789 * relations such as signum(1/x) = signum(x), where x is +Infinity or
1790 * -Infinity. Prior to this fix, we always formatted zero values as if
1791 * they were positive. Liu 7/6/98.
1792 */
1793 if (digitList.isZero()) {
1794 digitList.decimalAt = 0; // Normalize
1795 }
1796
1797 if (useExponentialNotation) {
1798 int iFieldStart = result.length();
1799 int iFieldEnd = -1;
1800 int fFieldStart = -1;
1801
1802 // Minimum integer digits are handled in exponential format by
1803 // adjusting the exponent. For example, 0.01234 with 3 minimum
1804 // integer digits is "123.4E-4".
1805 // Maximum integer digits are interpreted as indicating the
1806 // repeating range. This is useful for engineering notation, in
1807 // which the exponent is restricted to a multiple of 3. For
1808 // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
1809 // If maximum integer digits are > 1 and are larger than
1810 // minimum integer digits, then minimum integer digits are
1811 // ignored.
1812 int exponent = digitList.decimalAt;
1813 int repeat = maxIntDigits;
1814 int minimumIntegerDigits = minIntDigits;
1815 if (repeat > 1 && repeat > minIntDigits) {
1816 // A repeating range is defined; adjust to it as follows.
1817 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
1818 // -3,-4,-5=>-6, etc. This takes into account that the
1819 // exponent we have here is off by one from what we expect;
1820 // it is for the format 0.MMMMMx10^n.
1821 if (exponent >= 1) {
1822 exponent = ((exponent - 1) / repeat) * repeat;
1823 } else {
1824 // integer division rounds towards 0
2024 // after the decimal but before any significant digits. These
2025 // are only output if abs(number being formatted) < 1.0.
2026 if (-1-i > (digitList.decimalAt-1)) {
2027 result.append(zero);
2028 continue;
2029 }
2030
2031 // Output a digit, if we have any precision left, or a
2032 // zero if we don't. We don't want to output noise digits.
2033 if (!isInteger && digitIndex < digitList.count) {
2034 result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
2035 } else {
2036 result.append(zero);
2037 }
2038 }
2039
2040 // Record field information for caller.
2041 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
2042 fFieldStart, result.length(), result);
2043 }
2044 }
2045
2046 /**
2047 * Appends the String <code>string</code> to <code>result</code>.
2048 * <code>delegate</code> is notified of all the
2049 * <code>FieldPosition</code>s in <code>positions</code>.
2050 * <p>
2051 * If one of the <code>FieldPosition</code>s in <code>positions</code>
2052 * identifies a <code>SIGN</code> attribute, it is mapped to
2053 * <code>signAttribute</code>. This is used
2054 * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
2055 * attribute as necessary.
2056 * <p>
2057 * This is used by <code>subformat</code> to add the prefix/suffix.
2058 */
2059 private void append(StringBuffer result, String string,
2060 FieldDelegate delegate,
2061 FieldPosition[] positions,
2062 Format.Field signAttribute) {
2063 int start = result.length();
2269 private static final int STATUS_LENGTH = 2;
2270
2271 /**
2272 * Parse the given text into a number. The text is parsed beginning at
2273 * parsePosition, until an unparseable character is seen.
2274 * @param text The string to parse.
2275 * @param parsePosition The position at which to being parsing. Upon
2276 * return, the first unparseable character.
2277 * @param digits The DigitList to set to the parsed value.
2278 * @param isExponent If true, parse an exponent. This means no
2279 * infinite values and integer only.
2280 * @param status Upon return contains boolean status flags indicating
2281 * whether the value was infinite and whether it was positive.
2282 */
2283 private final boolean subparse(String text, ParsePosition parsePosition,
2284 String positivePrefix, String negativePrefix,
2285 DigitList digits, boolean isExponent,
2286 boolean status[]) {
2287 int position = parsePosition.index;
2288 int oldStart = parsePosition.index;
2289 boolean gotPositive, gotNegative;
2290
2291 // check for positivePrefix; take longest
2292 gotPositive = text.regionMatches(position, positivePrefix, 0,
2293 positivePrefix.length());
2294 gotNegative = text.regionMatches(position, negativePrefix, 0,
2295 negativePrefix.length());
2296
2297 if (gotPositive && gotNegative) {
2298 if (positivePrefix.length() > negativePrefix.length()) {
2299 gotNegative = false;
2300 } else if (positivePrefix.length() < negativePrefix.length()) {
2301 gotPositive = false;
2302 }
2303 }
2304
2305 if (gotPositive) {
2306 position += positivePrefix.length();
2307 } else if (gotNegative) {
2308 position += negativePrefix.length();
2309 } else {
2310 parsePosition.errorIndex = position;
2311 return false;
2312 }
2313
2314 position = subparseNumber(text, position, digits, true, isExponent, status);
2315 if (position == -1) {
2316 parsePosition.index = oldStart;
2317 parsePosition.errorIndex = oldStart;
2318 return false;
2319 }
2320
2321 // check for suffix
2322 if (!isExponent) {
2323 if (gotPositive) {
2324 gotPositive = text.regionMatches(position,positiveSuffix,0,
2325 positiveSuffix.length());
2326 }
2327 if (gotNegative) {
2328 gotNegative = text.regionMatches(position,negativeSuffix,0,
2329 negativeSuffix.length());
2330 }
2331
2332 // if both match, take longest
2333 if (gotPositive && gotNegative) {
2334 if (positiveSuffix.length() > negativeSuffix.length()) {
2335 gotNegative = false;
2336 } else if (positiveSuffix.length() < negativeSuffix.length()) {
2337 gotPositive = false;
2338 }
2339 }
2340
2341 // fail if neither or both
2342 if (gotPositive == gotNegative) {
2343 parsePosition.errorIndex = position;
2344 return false;
2345 }
2346
2347 parsePosition.index = position +
2348 (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
2349 } else {
2350 parsePosition.index = position;
2351 }
2352
2353 status[STATUS_POSITIVE] = gotPositive;
2354 if (parsePosition.index == oldStart) {
2355 parsePosition.errorIndex = position;
2356 return false;
2357 }
2358 return true;
2359 }
2360
2361 /**
2362 * Parses a number from the given {@code text}. The text is parsed
2363 * beginning at position, until an unparseable character is seen.
2364 *
2365 * @param text the string to parse
2366 * @param position the position at which parsing begins
2367 * @param digits the DigitList to set to the parsed value
2368 * @param checkExponent whether to check for exponential number
2369 * @param isExponent if the exponential part is encountered
2370 * @param status upon return contains boolean status flags indicating
2371 * whether the value is infinite and whether it is
2372 * positive
2373 * @return returns the position of the first unparseable character or
2374 * -1 in case of no valid number parsed
2375 */
2376 int subparseNumber(String text, int position,
2377 DigitList digits, boolean checkExponent,
2378 boolean isExponent, boolean status[]) {
2379 // process digits or Inf, find decimal position
2380 status[STATUS_INFINITE] = false;
2381 if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
2382 symbols.getInfinity().length())) {
2383 position += symbols.getInfinity().length();
2384 status[STATUS_INFINITE] = true;
2385 } else {
2386 // We now have a string of digits, possibly with grouping symbols,
2387 // and decimal points. We want to process these into a DigitList.
2388 // We don't want to put a bunch of leading zeros into the DigitList
2389 // though, so we keep track of the location of the decimal point,
2390 // put only significant digits into the DigitList, and adjust the
2391 // exponent as needed.
2392
2393 digits.decimalAt = digits.count = 0;
2394 char zero = symbols.getZeroDigit();
2395 char decimal = isCurrencyFormat ?
2396 symbols.getMonetaryDecimalSeparator() :
2397 symbols.getDecimalSeparator();
2398 char grouping = symbols.getGroupingSeparator();
2399 String exponentString = symbols.getExponentSeparator();
2400 boolean sawDecimal = false;
2401 boolean sawExponent = false;
2402 boolean sawDigit = false;
2403 int exponent = 0; // Set to the exponent value, if any
2404
2405 // We have to track digitCount ourselves, because digits.count will
2406 // pin when the maximum allowable digits is reached.
2407 int digitCount = 0;
2408
2409 int backup = -1;
2410 for (; position < text.length(); ++position) {
2411 char ch = text.charAt(position);
2412
2413 /* We recognize all digit ranges, not only the Latin digit range
2414 * '0'..'9'. We do so by using the Character.digit() method,
2415 * which converts a valid Unicode digit to the range 0..9.
2416 *
2417 * The character 'ch' may be a digit. If so, place its value
2418 * from 0 to 9 in 'digit'. First try using the locale digit,
2419 * which may or MAY NOT be a standard Unicode digit range. If
2420 * this fails, try using the standard Unicode digit ranges by
2421 * calling Character.digit(). If this also fails, digit will
2422 * have a value outside the range 0..9.
2423 */
2424 int digit = ch - zero;
2425 if (digit < 0 || digit > 9) {
2426 digit = Character.digit(ch, 10);
2427 }
2428
2429 if (digit == 0) {
2453 digits.append((char)(digit + '0'));
2454
2455 // Cancel out backup setting (see grouping handler below)
2456 backup = -1;
2457 } else if (!isExponent && ch == decimal) {
2458 // If we're only parsing integers, or if we ALREADY saw the
2459 // decimal, then don't parse this one.
2460 if (isParseIntegerOnly() || sawDecimal) {
2461 break;
2462 }
2463 digits.decimalAt = digitCount; // Not digits.count!
2464 sawDecimal = true;
2465 } else if (!isExponent && ch == grouping && isGroupingUsed()) {
2466 if (sawDecimal) {
2467 break;
2468 }
2469 // Ignore grouping characters, if we are using them, but
2470 // require that they be followed by a digit. Otherwise
2471 // we backup and reprocess them.
2472 backup = position;
2473 } else if (checkExponent && !isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
2474 && !sawExponent) {
2475 // Process the exponent by recursively calling this method.
2476 ParsePosition pos = new ParsePosition(position + exponentString.length());
2477 boolean[] stat = new boolean[STATUS_LENGTH];
2478 DigitList exponentDigits = new DigitList();
2479
2480 if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
2481 exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
2482 position = pos.index; // Advance past the exponent
2483 exponent = (int)exponentDigits.getLong();
2484 if (!stat[STATUS_POSITIVE]) {
2485 exponent = -exponent;
2486 }
2487 sawExponent = true;
2488 }
2489 break; // Whether we fail or succeed, we exit this loop
2490 } else {
2491 break;
2492 }
2493 }
2494
2495 if (backup != -1) {
2496 position = backup;
2497 }
2498
2499 // If there was no decimal point we have an integer
2500 if (!sawDecimal) {
2501 digits.decimalAt = digitCount; // Not digits.count!
2502 }
2503
2504 // Adjust for exponent, if any
2505 digits.decimalAt += exponent;
2506
2507 // If none of the text string was recognized. For example, parse
2508 // "x" with pattern "#0.00" (return index and error index both 0)
2509 // parse "$" with pattern "$#0.00". (return index 0 and error
2510 // index 1).
2511 if (!sawDigit && digitCount == 0) {
2512 return -1;
2513 }
2514 }
2515 return position;
2516
2517 }
2518
2519 /**
2520 * Returns a copy of the decimal format symbols, which is generally not
2521 * changed by the programmer or user.
2522 * @return a copy of the desired DecimalFormatSymbols
2523 * @see java.text.DecimalFormatSymbols
2524 */
2525 public DecimalFormatSymbols getDecimalFormatSymbols() {
2526 try {
2527 // don't allow multiple references
2528 return (DecimalFormatSymbols) symbols.clone();
2529 } catch (Exception foo) {
2530 return null; // should never happen
2531 }
2532 }
2533
2534
2535 /**
2536 * Sets the decimal format symbols, which is generally not changed
|