classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

java.text.DecimalFormat


From: Guilhem Lavaux
Subject: java.text.DecimalFormat
Date: Sun, 11 Apr 2004 09:51:33 +0200
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030630

Hi,

Here is patch to implement attributes and fixes the exponential notation. The formatting has been rebuilt to be able to construct the output string without inserting characters in the middle of the string.

ChangeLog entry:

2004-04-11  Guilhem Lavaux <address@hidden>

        * java/text/DecimalFormat.java
        (scanFix): Build attribute array. Fixed error reporting.
        (applyPatternWithSymbols): Store attributes for the prefix and
        suffix.
        (formatInternal): New method. Changed the way the string is
        computed. Implemented attributes. Cleant up rounding in
        exponential notation.
        (format): Use formatInternal.
        (formatToCharacterIterator): New method.
        (exponentRound, negativePrefixRanges, positivePrefixRanges,
        negativePrefixAttrs, positivePrefixAttrs, negativeSuffixRanges,
        positiveSuffixRanges, negativeSuffixAttrs, positiveSuffixAttrs):
        New fields.

Cheers,

Guilhem.
Index: java/text/DecimalFormat.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/text/DecimalFormat.java,v
retrieving revision 1.12
diff -u -b -B -r1.12 DecimalFormat.java
--- java/text/DecimalFormat.java        1 Apr 2004 12:28:12 -0000       1.12
+++ java/text/DecimalFormat.java        10 Apr 2004 17:07:21 -0000
@@ -37,12 +37,16 @@
 
 package java.text;
 
+import gnu.java.text.AttributedFormatBuffer;
+import gnu.java.text.FormatBuffer;
+import gnu.java.text.FormatCharacterIterator;
+import gnu.java.text.StringFormatBuffer;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.util.Currency;
+import java.util.HashMap;
 import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.io.ObjectInputStream;
-import java.io.IOException;
 
 /**
  * @author Tom Tromey <address@hidden>
@@ -58,37 +62,48 @@
 {
   // This is a helper for applyPatternWithSymbols.  It reads a prefix
   // or a suffix.  It can cause some side-effects.
-  private final int scanFix (String pattern, int index, StringBuffer buf,
+  private final int scanFix (String pattern, int index, FormatBuffer buf,
                             String patChars, DecimalFormatSymbols syms,
                             boolean is_suffix)
   {
     int len = pattern.length();
-    buf.setLength(0);
+    boolean quoteStarted = false;
+    buf.clear();
+    
     boolean multiplierSet = false;
     while (index < len)
       {
        char c = pattern.charAt(index);
+
+       if (quoteStarted)
+         {
+           if (c == '\'')
+             quoteStarted = false;
+           else
+             buf.append(c);
+           index++;
+           continue;
+         }
+
        if (c == '\'' && index + 1 < len
            && pattern.charAt(index + 1) == '\'')
          {
            buf.append(c);
-           ++index;
+           index++;
          }
-       else if (c == '\'' && index + 2 < len
-                && pattern.charAt(index + 2) == '\'')
+       else if (c == '\'')
          {
-           buf.append(pattern.charAt(index + 1));
-           index += 2;
+           quoteStarted = true;
          }
        else if (c == '\u00a4')
          {
            if (index + 1 < len && pattern.charAt(index + 1) == '\u00a4')
              {
-               buf.append(syms.getInternationalCurrencySymbol());
-               ++index;
+               buf.append(syms.getInternationalCurrencySymbol(), 
NumberFormat.Field.CURRENCY);
+               index++;
              }
            else
-             buf.append(syms.getCurrencySymbol());
+             buf.append(syms.getCurrencySymbol(), NumberFormat.Field.CURRENCY);
          }
        else if (c == syms.getPercent())
          {
@@ -97,7 +112,7 @@
                                                  "- index: " + index);
            multiplierSet = true;
            multiplier = 100;
-           buf.append(c);
+           buf.append(c, NumberFormat.Field.PERCENT);
          }
        else if (c == syms.getPerMill())
          {
@@ -106,7 +121,7 @@
                                                  "- index: " + index);
            multiplierSet = true;
            multiplier = 1000;
-           buf.append(c);
+           buf.append(c, NumberFormat.Field.PERMILLE);
          }
        else if (patChars.indexOf(c) != -1)
          {
@@ -115,9 +130,12 @@
          }
        else
          buf.append(c);
-       ++index;
+       index++;
       }
 
+    if (quoteStarted)
+      throw new IllegalArgumentException ("pattern is lacking a closing 
quote");
+
     return index;
   }
 
@@ -259,6 +277,16 @@
            useExponentialNotation = true;
            minExponentDigits = (byte) zeroCount;
          }
+
+       maximumIntegerDigits = groupingSize;
+       groupingSize = 0;
+       if (maximumIntegerDigits > minimumIntegerDigits && maximumIntegerDigits 
> 0)
+         {
+           minimumIntegerDigits = 1;
+           exponentRound = maximumIntegerDigits;
+         }
+       else
+         exponentRound = 1;
       }
 
     return index;
@@ -304,17 +332,23 @@
     minimumFractionDigits = 0;
     minimumIntegerDigits = 1;
 
-    StringBuffer buf = new StringBuffer ();
+    AttributedFormatBuffer buf = new AttributedFormatBuffer ();
     String patChars = patternChars (syms);
 
     int max = pattern.length();
     int index = scanFix (pattern, 0, buf, patChars, syms, false);
-    positivePrefix = buf.toString();
+    buf.sync();
+    positivePrefix = buf.getBuffer().toString();
+    positivePrefixRanges = buf.getRanges();
+    positivePrefixAttrs = buf.getAttributes();
 
     index = scanFormat (pattern, index, patChars, syms, true);
 
     index = scanFix (pattern, index, buf, patChars, syms, true);
-    positiveSuffix = buf.toString();
+    buf.sync();
+    positiveSuffix = buf.getBuffer().toString();
+    positiveSuffixRanges = buf.getRanges();
+    positiveSuffixAttrs = buf.getAttributes();
 
     if (index == pattern.length())
       {
@@ -329,14 +363,20 @@
                                              "expected - index: " + index);
 
        index = scanFix (pattern, index + 1, buf, patChars, syms, false);
-       negativePrefix = buf.toString();
+       buf.sync();
+       negativePrefix = buf.getBuffer().toString();
+       negativePrefixRanges = buf.getRanges();
+       negativePrefixAttrs = buf.getAttributes();
 
        // We parse the negative format for errors but we don't let
        // it side-effect this object.
        index = scanFormat (pattern, index, patChars, syms, false);
 
        index = scanFix (pattern, index, buf, patChars, syms, true);
-       negativeSuffix = buf.toString();
+       buf.sync();
+       negativeSuffix = buf.getBuffer().toString();
+       negativeSuffixRanges = buf.getRanges();
+       negativeSuffixAttrs = buf.getAttributes();
 
        if (index != pattern.length())
          throw new IllegalArgumentException ("end of pattern expected " +
@@ -409,39 +449,43 @@
            && useExponentialNotation == dup.useExponentialNotation);
   }
 
-  public StringBuffer format (double number, StringBuffer dest,
+  protected void formatInternal (double number, FormatBuffer dest,
                              FieldPosition fieldPos)
   {
     // A very special case.
     if (Double.isNaN(number))
       {
        dest.append(symbols.getNaN());
-       if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
+       if (fieldPos != null && 
+           (fieldPos.getField() == INTEGER_FIELD ||
+            fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
          {
            int index = dest.length();
            fieldPos.setBeginIndex(index - symbols.getNaN().length());
            fieldPos.setEndIndex(index);
          }
-       return dest;
+       return;
       }
 
     boolean is_neg = number < 0;
     if (is_neg)
       {
        if (negativePrefix != null)
-         dest.append(negativePrefix);
+         dest.append(negativePrefix, negativePrefixRanges, 
negativePrefixAttrs);
        else
          {
-           dest.append(symbols.getMinusSign());
-           dest.append(positivePrefix);
+           dest.append(symbols.getMinusSign(), NumberFormat.Field.SIGN);
+           dest.append(positivePrefix, positivePrefixRanges, 
positivePrefixAttrs);
          }
        number = - number;
       }
     else
-      dest.append(positivePrefix);
+      dest.append(positivePrefix, positivePrefixRanges, positivePrefixAttrs);
 
     int integerBeginIndex = dest.length();
     int integerEndIndex = 0;
+    int zeroStart = symbols.getZeroDigit() - '0';
+
     if (Double.isInfinite (number))
       {
        dest.append(symbols.getInfinity());
@@ -457,6 +501,7 @@
        if (useExponentialNotation)
          {
            exponent = (long) Math.floor (Math.log(number) / Math.log(10));
+           exponent = exponent - (exponent % exponentRound);
            if (minimumIntegerDigits > 0)
              exponent -= minimumIntegerDigits - 1;
            baseNumber = (number / Math.pow(10.0, exponent));
@@ -468,22 +513,32 @@
        baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1);
 
        int index = dest.length();
-       double intPart = Math.floor(baseNumber);
-       int count = 0;
-       while (count < maximumIntegerDigits
-              && (intPart > 0 || count < minimumIntegerDigits))
+       //double intPart = Math.floor(baseNumber);
+       String intPart = Long.toString((long)Math.floor(baseNumber));
+       int count, groupPosition = intPart.length();
+
+       dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
+
+       for (count = 0; count < minimumIntegerDigits-intPart.length(); count++)
+         dest.append(symbols.getZeroDigit());
+
+       for (count = 0;
+            count < maximumIntegerDigits && count < intPart.length();
+            count++)
          {
-           long dig = (long) (intPart % 10);
-           intPart = Math.floor(intPart / 10);
+           int dig = intPart.charAt(count);
 
            // Append group separator if required.
-           if (groupingUsed && count > 0 && groupingSize != 0 && count % 
groupingSize == 0)
-             dest.insert(index, symbols.getGroupingSeparator());
-
-           dest.insert(index, (char) (symbols.getZeroDigit() + dig));
+           if (groupingUsed && count > 0 && groupingSize != 0 && groupPosition 
% groupingSize == 0)
+             {
+               dest.append(symbols.getGroupingSeparator(), 
NumberFormat.Field.GROUPING_SEPARATOR);
+               dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
+             }
+           dest.append((char) (zeroStart + dig));
 
-           ++count;
+           groupPosition--;
          }
+       dest.setDefaultAttribute(null);
 
        integerEndIndex = dest.length();
 
@@ -491,10 +546,24 @@
        int consecutive_zeros = 0;
        int total_digits = 0;
 
+       int localMaximumFractionDigits = maximumFractionDigits;
+
+       if (useExponentialNotation)
+         localMaximumFractionDigits += minimumIntegerDigits - count;
+
        // Strip integer part from NUMBER.
        double fracPart = baseNumber - Math.floor(baseNumber);
+       
+       if ( ((fracPart != 0 || minimumFractionDigits > 0) && 
localMaximumFractionDigits > 0)
+            || decimalSeparatorAlwaysShown)
+         {
+           dest.append (symbols.getDecimalSeparator(), 
NumberFormat.Field.DECIMAL_SEPARATOR);
+         }
+
+
+       dest.setDefaultAttribute(NumberFormat.Field.FRACTION);
        for (count = 0;
-            count < maximumFractionDigits
+            count < localMaximumFractionDigits
               && (fracPart != 0 || count < minimumFractionDigits);
             ++count)
          {
@@ -517,55 +586,76 @@
                                    total_digits - minimumFractionDigits);
        if (extra_zeros > 0)
          {
-           dest.setLength(dest.length() - extra_zeros);
+           dest.cutTail(extra_zeros);
            total_digits -= extra_zeros;
-         }
-
-       // If required, add the decimal symbol.
-       if (decimalSeparatorAlwaysShown
-           || total_digits > 0)
-         {
-           dest.insert(decimal_index, symbols.getDecimalSeparator());
-           if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
-             {
-               fieldPos.setBeginIndex(decimal_index + 1);
-               fieldPos.setEndIndex(dest.length());
-             }
+           if (total_digits == 0 && !decimalSeparatorAlwaysShown)
+             dest.cutTail(1);
          }
 
        // Finally, print the exponent.
        if (useExponentialNotation)
          {
-           dest.append(symbols.getExponential());
+           dest.append(symbols.getExponential(), 
NumberFormat.Field.EXPONENT_SYMBOL);      
            if (exponent < 0)
              {
-               dest.append (symbols.getMinusSign ());
+               dest.append (symbols.getMinusSign (), 
NumberFormat.Field.EXPONENT_SIGN);
                exponent = - exponent;
              }
            index = dest.length();
+           dest.setDefaultAttribute(NumberFormat.Field.EXPONENT);
+           String exponentString = Long.toString ((long) exponent);
+           
+           for (count = 0; count < minExponentDigits-exponentString.length();
+                count++)
+             dest.append((char) symbols.getZeroDigit());
+
            for (count = 0;
-                exponent > 0 || count < minExponentDigits;
+                count < exponentString.length();
                 ++count)
              {
-               long dig = exponent % 10;
-               exponent /= 10;
-               dest.insert(index, (char) (symbols.getZeroDigit() + dig));
+               int dig = exponentString.charAt(count);
+               dest.append((char) (zeroStart + dig));
              }
          }
       }
 
-    if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
+    if (fieldPos != null && 
+       (fieldPos.getField() == INTEGER_FIELD ||
+        fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
       {
        fieldPos.setBeginIndex(integerBeginIndex);
        fieldPos.setEndIndex(integerEndIndex);
       }
 
-    dest.append((is_neg && negativeSuffix != null)
-               ? negativeSuffix
-               : positiveSuffix);
+    if (is_neg && negativeSuffix != null)
+      dest.append(negativeSuffix, negativeSuffixRanges, negativeSuffixAttrs);
+    else
+      dest.append(positiveSuffix, positiveSuffixRanges, positiveSuffixAttrs);
+  }
+
+  public StringBuffer format (double number, StringBuffer dest,
+                             FieldPosition fieldPos)
+  {
+    formatInternal (number, new StringFormatBuffer(dest), fieldPos);
     return dest;
   }
 
+  public AttributedCharacterIterator formatToCharacterIterator (Object value)
+  {
+    AttributedFormatBuffer sbuf = new AttributedFormatBuffer();
+
+    if (value instanceof Number)
+      formatInternal(((Number) value).doubleValue(), sbuf, null);
+    else
+      throw new IllegalArgumentException 
+       ("Cannot format given Object as a Number");
+    
+    sbuf.sync();
+    return new FormatCharacterIterator(sbuf.getBuffer().toString(), 
+                                      sbuf.getRanges(), 
+                                      sbuf.getAttributes());
+  }
+
   public StringBuffer format (long number, StringBuffer dest,
                              FieldPosition fieldPos)
   {
@@ -964,7 +1054,7 @@
     // digits.  Past that we need hash marks up to the grouping
     // separator (and one beyond).
     int total_digits = Math.max(minimumIntegerDigits,
-                               groupingUsed ? groupingSize + 1: 0);
+                               groupingUsed ? groupingSize + 1: groupingSize);
     for (int i = 0; i < total_digits - minimumIntegerDigits; ++i)
       mainPattern.append(syms.getDigit());
     for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i)
@@ -1022,11 +1112,16 @@
   private boolean decimalSeparatorAlwaysShown;
   private byte groupingSize;
   private byte minExponentDigits;
+  private int exponentRound;
   private int multiplier;
   private String negativePrefix;
   private String negativeSuffix;
   private String positivePrefix;
   private String positiveSuffix;
+  private int[] negativePrefixRanges, positivePrefixRanges;
+  private HashMap[] negativePrefixAttrs, positivePrefixAttrs;
+  private int[] negativeSuffixRanges, positiveSuffixRanges;
+  private HashMap[] negativeSuffixAttrs, positiveSuffixAttrs;
   private int serialVersionOnStream = 1;
   private DecimalFormatSymbols symbols;
   private boolean useExponentialNotation;

Attachment: pgpUoTradHTXW.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]