source: trunk/gcc/libjava/java/text/DecimalFormat.java

Last change on this file was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 25.9 KB
Line 
1/* DecimalFormat.java -- Formats and parses numbers
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3
4This file is part of GNU Classpath.
5
6GNU Classpath is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Classpath is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Classpath; see the file COPYING. If not, write to the
18Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1902111-1307 USA.
20
21Linking this library statically or dynamically with other modules is
22making a combined work based on this library. Thus, the terms and
23conditions of the GNU General Public License cover the whole
24combination.
25
26As a special exception, the copyright holders of this library give you
27permission to link this library with independent modules to produce an
28executable, regardless of the license terms of these independent
29modules, and to copy and distribute the resulting executable under
30terms of your choice, provided that you also meet, for each linked
31independent module, the terms and conditions of the license of that
32module. An independent module is a module which is not derived from
33or based on this library. If you modify this library, you may extend
34this exception to your version of the library, but you are not
35obligated to do so. If you do not wish to do so, delete this
36exception statement from your version. */
37
38package java.text;
39
40import java.util.Locale;
41import java.util.MissingResourceException;
42import java.util.ResourceBundle;
43import java.io.ObjectInputStream;
44import java.io.IOException;
45
46/**
47 * @author Tom Tromey <tromey@cygnus.com>
48 * @date March 4, 1999
49 */
50/* Written using "Java Class Libraries", 2nd edition, plus online
51 * API docs for JDK 1.2 from http://www.javasoft.com.
52 * Status: Believed complete and correct to 1.2.
53 * Note however that the docs are very unclear about how format parsing
54 * should work. No doubt there are problems here.
55 */
56public class DecimalFormat extends NumberFormat
57{
58 // This is a helper for applyPatternWithSymbols. It reads a prefix
59 // or a suffix. It can cause some side-effects.
60 private final int scanFix (String pattern, int index, StringBuffer buf,
61 String patChars, DecimalFormatSymbols syms,
62 boolean is_suffix)
63 {
64 int len = pattern.length();
65 buf.setLength(0);
66 boolean multiplierSet = false;
67 while (index < len)
68 {
69 char c = pattern.charAt(index);
70 if (c == '\'' && index + 1 < len
71 && pattern.charAt(index + 1) == '\'')
72 {
73 buf.append(c);
74 ++index;
75 }
76 else if (c == '\'' && index + 2 < len
77 && pattern.charAt(index + 2) == '\'')
78 {
79 buf.append(pattern.charAt(index + 1));
80 index += 2;
81 }
82 else if (c == '\u00a4')
83 {
84 if (index + 1 < len && pattern.charAt(index + 1) == '\u00a4')
85 {
86 buf.append(syms.getInternationalCurrencySymbol());
87 ++index;
88 }
89 else
90 buf.append(syms.getCurrencySymbol());
91 }
92 else if (is_suffix && c == syms.getPercent())
93 {
94 if (multiplierSet)
95 throw new IllegalArgumentException ("multiplier already set " +
96 "- index: " + index);
97 multiplierSet = true;
98 multiplier = 100;
99 buf.append(c);
100 }
101 else if (is_suffix && c == syms.getPerMill())
102 {
103 if (multiplierSet)
104 throw new IllegalArgumentException ("multiplier already set " +
105 "- index: " + index);
106 multiplierSet = true;
107 multiplier = 1000;
108 buf.append(c);
109 }
110 else if (patChars.indexOf(c) != -1)
111 {
112 // This is a pattern character.
113 break;
114 }
115 else
116 buf.append(c);
117 ++index;
118 }
119
120 return index;
121 }
122
123 // A helper which reads a number format.
124 private final int scanFormat (String pattern, int index,
125 String patChars, DecimalFormatSymbols syms,
126 boolean is_positive)
127 {
128 int max = pattern.length();
129
130 int countSinceGroup = 0;
131 int zeroCount = 0;
132 boolean saw_group = false;
133
134 //
135 // Scan integer part.
136 //
137 while (index < max)
138 {
139 char c = pattern.charAt(index);
140
141 if (c == syms.getDigit())
142 {
143 if (zeroCount > 0)
144 throw new IllegalArgumentException ("digit mark following " +
145 "zero - index: " + index);
146 ++countSinceGroup;
147 }
148 else if (c == syms.getZeroDigit())
149 {
150 ++zeroCount;
151 ++countSinceGroup;
152 }
153 else if (c == syms.getGroupingSeparator())
154 {
155 countSinceGroup = 0;
156 saw_group = true;
157 }
158 else
159 break;
160
161 ++index;
162 }
163
164 // We can only side-effect when parsing the positive format.
165 if (is_positive)
166 {
167 groupingUsed = saw_group;
168 groupingSize = (byte) countSinceGroup;
169 minimumIntegerDigits = zeroCount;
170 }
171
172 // Early termination.
173 if (index == max || pattern.charAt(index) == syms.getGroupingSeparator())
174 {
175 if (is_positive)
176 decimalSeparatorAlwaysShown = false;
177 return index;
178 }
179
180 if (pattern.charAt(index) == syms.getDecimalSeparator())
181 {
182 ++index;
183
184 //
185 // Scan fractional part.
186 //
187 int hashCount = 0;
188 zeroCount = 0;
189 while (index < max)
190 {
191 char c = pattern.charAt(index);
192 if (c == syms.getZeroDigit())
193 {
194 if (hashCount > 0)
195 throw new IllegalArgumentException ("zero mark " +
196 "following digit - index: " + index);
197 ++zeroCount;
198 }
199 else if (c == syms.getDigit())
200 {
201 ++hashCount;
202 }
203 else if (c != syms.getExponential()
204 && c != syms.getPatternSeparator()
205 && patChars.indexOf(c) != -1)
206 throw new IllegalArgumentException ("unexpected special " +
207 "character - index: " + index);
208 else
209 break;
210
211 ++index;
212 }
213
214 if (is_positive)
215 {
216 maximumFractionDigits = hashCount + zeroCount;
217 minimumFractionDigits = zeroCount;
218 }
219
220 if (index == max)
221 return index;
222 }
223
224 if (pattern.charAt(index) == syms.getExponential())
225 {
226 //
227 // Scan exponential format.
228 //
229 zeroCount = 0;
230 ++index;
231 while (index < max)
232 {
233 char c = pattern.charAt(index);
234 if (c == syms.getZeroDigit())
235 ++zeroCount;
236 else if (c == syms.getDigit())
237 {
238 if (zeroCount > 0)
239 throw new
240 IllegalArgumentException ("digit mark following zero " +
241 "in exponent - index: " +
242 index);
243 }
244 else if (patChars.indexOf(c) != -1)
245 throw new IllegalArgumentException ("unexpected special " +
246 "character - index: " +
247 index);
248 else
249 break;
250
251 ++index;
252 }
253
254 if (is_positive)
255 {
256 useExponentialNotation = true;
257 minExponentDigits = (byte) zeroCount;
258 }
259 }
260
261 return index;
262 }
263
264 // This helper function creates a string consisting of all the
265 // characters which can appear in a pattern and must be quoted.
266 private final String patternChars (DecimalFormatSymbols syms)
267 {
268 StringBuffer buf = new StringBuffer ();
269 buf.append(syms.getDecimalSeparator());
270 buf.append(syms.getDigit());
271 buf.append(syms.getExponential());
272 buf.append(syms.getGroupingSeparator());
273 // Adding this one causes pattern application to fail.
274 // Of course, omitting is causes toPattern to fail.
275 // ... but we already have bugs there. FIXME.
276 // buf.append(syms.getMinusSign());
277 buf.append(syms.getPatternSeparator());
278 buf.append(syms.getPercent());
279 buf.append(syms.getPerMill());
280 buf.append(syms.getZeroDigit());
281 buf.append('\u00a4');
282 return buf.toString();
283 }
284
285 private final void applyPatternWithSymbols (String pattern,
286 DecimalFormatSymbols syms)
287 {
288 // Initialize to the state the parser expects.
289 negativePrefix = "";
290 negativeSuffix = "";
291 positivePrefix = "";
292 positiveSuffix = "";
293 decimalSeparatorAlwaysShown = false;
294 groupingSize = 0;
295 minExponentDigits = 0;
296 multiplier = 1;
297 useExponentialNotation = false;
298 groupingUsed = false;
299 maximumFractionDigits = 0;
300 maximumIntegerDigits = 309;
301 minimumFractionDigits = 0;
302 minimumIntegerDigits = 1;
303
304 StringBuffer buf = new StringBuffer ();
305 String patChars = patternChars (syms);
306
307 int max = pattern.length();
308 int index = scanFix (pattern, 0, buf, patChars, syms, false);
309 positivePrefix = buf.toString();
310
311 index = scanFormat (pattern, index, patChars, syms, true);
312
313 index = scanFix (pattern, index, buf, patChars, syms, true);
314 positiveSuffix = buf.toString();
315
316 if (index == pattern.length())
317 {
318 // No negative info.
319 negativePrefix = null;
320 negativeSuffix = null;
321 }
322 else
323 {
324 if (pattern.charAt(index) != syms.getPatternSeparator())
325 throw new IllegalArgumentException ("separator character " +
326 "expected - index: " + index);
327
328 index = scanFix (pattern, index + 1, buf, patChars, syms, false);
329 negativePrefix = buf.toString();
330
331 // We parse the negative format for errors but we don't let
332 // it side-effect this object.
333 index = scanFormat (pattern, index, patChars, syms, false);
334
335 index = scanFix (pattern, index, buf, patChars, syms, true);
336 negativeSuffix = buf.toString();
337
338 if (index != pattern.length())
339 throw new IllegalArgumentException ("end of pattern expected " +
340 "- index: " + index);
341 }
342 }
343
344 public void applyLocalizedPattern (String pattern)
345 {
346 // JCL p. 638 claims this throws a ParseException but p. 629
347 // contradicts this. Empirical tests with patterns of "0,###.0"
348 // and "#.#.#" corroborate the p. 629 statement that an
349 // IllegalArgumentException is thrown.
350 applyPatternWithSymbols (pattern, symbols);
351 }
352
353 public void applyPattern (String pattern)
354 {
355 // JCL p. 638 claims this throws a ParseException but p. 629
356 // contradicts this. Empirical tests with patterns of "0,###.0"
357 // and "#.#.#" corroborate the p. 629 statement that an
358 // IllegalArgumentException is thrown.
359 applyPatternWithSymbols (pattern, nonLocalizedSymbols);
360 }
361
362 public Object clone ()
363 {
364 DecimalFormat c = (DecimalFormat) super.clone ();
365 c.symbols = (DecimalFormatSymbols) symbols.clone ();
366 return c;
367 }
368
369 public DecimalFormat ()
370 {
371 this ("#,##0.###");
372 }
373
374 public DecimalFormat (String pattern)
375 {
376 this (pattern, new DecimalFormatSymbols ());
377 }
378
379 public DecimalFormat (String pattern, DecimalFormatSymbols symbols)
380 {
381 this.symbols = symbols;
382 applyPattern (pattern);
383 }
384
385 private final boolean equals (String s1, String s2)
386 {
387 if (s1 == null || s2 == null)
388 return s1 == s2;
389 return s1.equals(s2);
390 }
391
392 public boolean equals (Object obj)
393 {
394 if (! (obj instanceof DecimalFormat))
395 return false;
396 DecimalFormat dup = (DecimalFormat) obj;
397 return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
398 && groupingSize == dup.groupingSize
399 && minExponentDigits == dup.minExponentDigits
400 && multiplier == dup.multiplier
401 && equals(negativePrefix, dup.negativePrefix)
402 && equals(negativeSuffix, dup.negativeSuffix)
403 && equals(positivePrefix, dup.positivePrefix)
404 && equals(positiveSuffix, dup.positiveSuffix)
405 && symbols.equals(dup.symbols)
406 && useExponentialNotation == dup.useExponentialNotation);
407 }
408
409 public StringBuffer format (double number, StringBuffer dest,
410 FieldPosition fieldPos)
411 {
412 // A very special case.
413 if (Double.isNaN(number))
414 {
415 dest.append(symbols.getNaN());
416 if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
417 {
418 int index = dest.length();
419 fieldPos.setBeginIndex(index - symbols.getNaN().length());
420 fieldPos.setEndIndex(index);
421 }
422 return dest;
423 }
424
425 boolean is_neg = number < 0;
426 if (is_neg)
427 {
428 if (negativePrefix != null)
429 dest.append(negativePrefix);
430 else
431 {
432 dest.append(symbols.getMinusSign());
433 dest.append(positivePrefix);
434 }
435 number = - number;
436 }
437 else
438 dest.append(positivePrefix);
439
440 int integerBeginIndex = dest.length();
441 int integerEndIndex = 0;
442 if (Double.isInfinite (number))
443 {
444 dest.append(symbols.getInfinity());
445 integerEndIndex = dest.length();
446 }
447 else
448 {
449 number *= multiplier;
450
451 // Compute exponent.
452 long exponent = 0;
453 double baseNumber;
454 if (useExponentialNotation)
455 {
456 exponent = (long) Math.floor (Math.log(number) / Math.log(10));
457 if (minimumIntegerDigits > 0)
458 exponent -= minimumIntegerDigits - 1;
459 baseNumber = (long) (number / Math.pow(10.0, exponent));
460 }
461 else
462 baseNumber = number;
463
464 // Round to the correct number of digits.
465 baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1);
466
467 int index = dest.length();
468 double intPart = Math.floor(baseNumber);
469 int count = 0;
470 while (count < maximumIntegerDigits
471 && (intPart > 0 || count < minimumIntegerDigits))
472 {
473 long dig = (long) (intPart % 10);
474 intPart = Math.floor(intPart / 10);
475
476 // Append group separator if required.
477 if (groupingUsed && count > 0 && count % groupingSize == 0)
478 dest.insert(index, symbols.getGroupingSeparator());
479
480 dest.insert(index, (char) (symbols.getZeroDigit() + dig));
481
482 ++count;
483 }
484
485 integerEndIndex = dest.length();
486
487 int decimal_index = integerEndIndex;
488 int consecutive_zeros = 0;
489 int total_digits = 0;
490
491 // Strip integer part from NUMBER.
492 double fracPart = baseNumber - Math.floor(baseNumber);
493 for (count = 0;
494 count < maximumFractionDigits
495 && (fracPart != 0 || count < minimumFractionDigits);
496 ++count)
497 {
498 ++total_digits;
499 fracPart *= 10;
500 long dig = (long) fracPart;
501 if (dig == 0)
502 ++consecutive_zeros;
503 else
504 consecutive_zeros = 0;
505 dest.append((char) (symbols.getZeroDigit() + dig));
506
507 // Strip integer part from FRACPART.
508 fracPart = fracPart - Math.floor (fracPart);
509 }
510
511 // Strip extraneous trailing `0's. We can't always detect
512 // these in the loop.
513 int extra_zeros = Math.min (consecutive_zeros,
514 total_digits - minimumFractionDigits);
515 if (extra_zeros > 0)
516 {
517 dest.setLength(dest.length() - extra_zeros);
518 total_digits -= extra_zeros;
519 }
520
521 // If required, add the decimal symbol.
522 if (decimalSeparatorAlwaysShown
523 || total_digits > 0)
524 {
525 dest.insert(decimal_index, symbols.getDecimalSeparator());
526 if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
527 {
528 fieldPos.setBeginIndex(decimal_index + 1);
529 fieldPos.setEndIndex(dest.length());
530 }
531 }
532
533 // Finally, print the exponent.
534 if (useExponentialNotation)
535 {
536 dest.append(symbols.getExponential());
537 if (exponent < 0)
538 {
539 dest.append (symbols.getMinusSign ());
540 exponent = - exponent;
541 }
542 index = dest.length();
543 for (count = 0;
544 exponent > 0 || count < minExponentDigits;
545 ++count)
546 {
547 long dig = exponent % 10;
548 exponent /= 10;
549 dest.insert(index, (char) (symbols.getZeroDigit() + dig));
550 }
551 }
552 }
553
554 if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
555 {
556 fieldPos.setBeginIndex(integerBeginIndex);
557 fieldPos.setEndIndex(integerEndIndex);
558 }
559
560 dest.append((is_neg && negativeSuffix != null)
561 ? negativeSuffix
562 : positiveSuffix);
563 return dest;
564 }
565
566 public StringBuffer format (long number, StringBuffer dest,
567 FieldPosition fieldPos)
568 {
569 // If using exponential notation, we just format as a double.
570 if (useExponentialNotation)
571 return format ((double) number, dest, fieldPos);
572
573 boolean is_neg = number < 0;
574 if (is_neg)
575 {
576 if (negativePrefix != null)
577 dest.append(negativePrefix);
578 else
579 {
580 dest.append(symbols.getMinusSign());
581 dest.append(positivePrefix);
582 }
583 number = - number;
584 }
585 else
586 dest.append(positivePrefix);
587
588 int integerBeginIndex = dest.length();
589 int index = dest.length();
590 int count = 0;
591 while (count < maximumIntegerDigits
592 && (number > 0 || count < minimumIntegerDigits))
593 {
594 long dig = number % 10;
595 number /= 10;
596 // NUMBER and DIG will be less than 0 if the original number
597 // was the most negative long.
598 if (dig < 0)
599 {
600 dig = - dig;
601 number = - number;
602 }
603
604 // Append group separator if required.
605 if (groupingUsed && count > 0 && count % groupingSize == 0)
606 dest.insert(index, symbols.getGroupingSeparator());
607
608 dest.insert(index, (char) (symbols.getZeroDigit() + dig));
609
610 ++count;
611 }
612
613 if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
614 {
615 fieldPos.setBeginIndex(integerBeginIndex);
616 fieldPos.setEndIndex(dest.length());
617 }
618
619 if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0)
620 {
621 dest.append(symbols.getDecimalSeparator());
622 if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
623 {
624 fieldPos.setBeginIndex(dest.length());
625 fieldPos.setEndIndex(dest.length() + minimumFractionDigits);
626 }
627 }
628
629 for (count = 0; count < minimumFractionDigits; ++count)
630 dest.append(symbols.getZeroDigit());
631
632 dest.append((is_neg && negativeSuffix != null)
633 ? negativeSuffix
634 : positiveSuffix);
635 return dest;
636 }
637
638 public DecimalFormatSymbols getDecimalFormatSymbols ()
639 {
640 return symbols;
641 }
642
643 public int getGroupingSize ()
644 {
645 return groupingSize;
646 }
647
648 public int getMultiplier ()
649 {
650 return multiplier;
651 }
652
653 public String getNegativePrefix ()
654 {
655 return negativePrefix;
656 }
657
658 public String getNegativeSuffix ()
659 {
660 return negativeSuffix;
661 }
662
663 public String getPositivePrefix ()
664 {
665 return positivePrefix;
666 }
667
668 public String getPositiveSuffix ()
669 {
670 return positiveSuffix;
671 }
672
673 public int hashCode ()
674 {
675 int hash = (negativeSuffix.hashCode() ^ negativePrefix.hashCode()
676 ^positivePrefix.hashCode() ^ positiveSuffix.hashCode());
677 // FIXME.
678 return hash;
679 }
680
681 public boolean isDecimalSeparatorAlwaysShown ()
682 {
683 return decimalSeparatorAlwaysShown;
684 }
685
686 public Number parse (String str, ParsePosition pos)
687 {
688 // Our strategy is simple: copy the text into a buffer,
689 // translating or omitting locale-specific information. Then
690 // let Double or Long convert the number for us.
691
692 boolean is_neg = false;
693 int index = pos.getIndex();
694 StringBuffer buf = new StringBuffer ();
695
696 // We have to check both prefixes, because one might be empty.
697 // We want to pick the longest prefix that matches.
698 boolean got_pos = str.startsWith(positivePrefix, index);
699 String np = (negativePrefix != null
700 ? negativePrefix
701 : positivePrefix + symbols.getMinusSign());
702 boolean got_neg = str.startsWith(np, index);
703
704 if (got_pos && got_neg)
705 {
706 // By checking this way, we preserve ambiguity in the case
707 // where the negative format differs only in suffix. We
708 // check this again later.
709 if (np.length() > positivePrefix.length())
710 {
711 is_neg = true;
712 index += np.length();
713 }
714 else
715 index += positivePrefix.length();
716 }
717 else if (got_neg)
718 {
719 is_neg = true;
720 index += np.length();
721 }
722 else if (got_pos)
723 index += positivePrefix.length();
724 else
725 {
726 pos.setErrorIndex (index);
727 return null;
728 }
729
730 // FIXME: handle Inf and NaN.
731
732 // FIXME: do we have to respect minimum/maxmimum digit stuff?
733 // What about leading zeros? What about multiplier?
734
735 int start_index = index;
736 int max = str.length();
737 char zero = symbols.getZeroDigit();
738 int last_group = -1;
739 boolean int_part = true;
740 boolean exp_part = false;
741 for (; index < max; ++index)
742 {
743 char c = str.charAt(index);
744
745 // FIXME: what about grouping size?
746 if (groupingUsed && c == symbols.getGroupingSeparator())
747 {
748 if (last_group != -1
749 && (index - last_group) % groupingSize != 0)
750 {
751 pos.setErrorIndex(index);
752 return null;
753 }
754 last_group = index;
755 }
756 else if (c >= zero && c <= zero + 9)
757 {
758 buf.append((char) (c - zero + '0'));
759 exp_part = false;
760 }
761 else if (parseIntegerOnly)
762 break;
763 else if (c == symbols.getDecimalSeparator())
764 {
765 if (last_group != -1
766 && (index - last_group) % groupingSize != 0)
767 {
768 pos.setErrorIndex(index);
769 return null;
770 }
771 buf.append('.');
772 int_part = false;
773 }
774 else if (c == symbols.getExponential())
775 {
776 buf.append('E');
777 int_part = false;
778 exp_part = true;
779 }
780 else if (exp_part
781 && (c == '+' || c == '-' || c == symbols.getMinusSign()))
782 {
783 // For exponential notation.
784 buf.append(c);
785 }
786 else
787 break;
788 }
789
790 if (index == start_index)
791 {
792 // Didn't see any digits.
793 pos.setErrorIndex(index);
794 return null;
795 }
796
797 // Check the suffix. We must do this before converting the
798 // buffer to a number to handle the case of a number which is
799 // the most negative Long.
800 boolean got_pos_suf = str.startsWith(positiveSuffix, index);
801 String ns = (negativePrefix == null ? positiveSuffix : negativeSuffix);
802 boolean got_neg_suf = str.startsWith(ns, index);
803 if (is_neg)
804 {
805 if (! got_neg_suf)
806 {
807 pos.setErrorIndex(index);
808 return null;
809 }
810 }
811 else if (got_pos && got_neg && got_neg_suf)
812 {
813 is_neg = true;
814 }
815 else if (got_pos != got_pos_suf && got_neg != got_neg_suf)
816 {
817 pos.setErrorIndex(index);
818 return null;
819 }
820
821 String suffix = is_neg ? ns : positiveSuffix;
822 if (is_neg)
823 buf.insert(0, '-');
824
825 String t = buf.toString();
826 Number result = null;
827 try
828 {
829 result = new Long (t);
830 }
831 catch (NumberFormatException x1)
832 {
833 try
834 {
835 result = new Double (t);
836 }
837 catch (NumberFormatException x2)
838 {
839 }
840 }
841 if (result == null)
842 {
843 pos.setErrorIndex(index);
844 return null;
845 }
846
847 pos.setIndex(index + suffix.length());
848
849 return result;
850 }
851
852 public void setDecimalFormatSymbols (DecimalFormatSymbols newSymbols)
853 {
854 symbols = newSymbols;
855 }
856
857 public void setDecimalSeparatorAlwaysShown (boolean newValue)
858 {
859 decimalSeparatorAlwaysShown = newValue;
860 }
861
862 public void setGroupingSize (int groupSize)
863 {
864 groupingSize = (byte) groupSize;
865 }
866
867 public void setMaximumFractionDigits (int newValue)
868 {
869 maximumFractionDigits = Math.min(newValue, 340);
870 }
871
872 public void setMaximumIntegerDigits (int newValue)
873 {
874 maximumIntegerDigits = Math.min(newValue, 309);
875 }
876
877 public void setMinimumFractionDigits (int newValue)
878 {
879 minimumFractionDigits = Math.min(newValue, 340);
880 }
881
882 public void setMinimumIntegerDigits (int newValue)
883 {
884 minimumIntegerDigits = Math.min(newValue, 309);
885 }
886
887 public void setMultiplier (int newValue)
888 {
889 multiplier = newValue;
890 }
891
892 public void setNegativePrefix (String newValue)
893 {
894 negativePrefix = newValue;
895 }
896
897 public void setNegativeSuffix (String newValue)
898 {
899 negativeSuffix = newValue;
900 }
901
902 public void setPositivePrefix (String newValue)
903 {
904 positivePrefix = newValue;
905 }
906
907 public void setPositiveSuffix (String newValue)
908 {
909 positiveSuffix = newValue;
910 }
911
912 private final void quoteFix (StringBuffer buf, String text, String patChars)
913 {
914 int len = text.length();
915 for (int index = 0; index < len; ++index)
916 {
917 char c = text.charAt(index);
918 if (patChars.indexOf(c) != -1)
919 {
920 buf.append('\'');
921 buf.append(c);
922 buf.append('\'');
923 }
924 else
925 buf.append(c);
926 }
927 }
928
929 private final String computePattern (DecimalFormatSymbols syms)
930 {
931 StringBuffer mainPattern = new StringBuffer ();
932 // We have to at least emit a zero for the minimum number of
933 // digits. Past that we need hash marks up to the grouping
934 // separator (and one beyond).
935 int total_digits = Math.max(minimumIntegerDigits,
936 groupingUsed ? groupingSize + 1: 0);
937 for (int i = 0; i < total_digits - minimumIntegerDigits; ++i)
938 mainPattern.append(syms.getDigit());
939 for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i)
940 mainPattern.append(syms.getZeroDigit());
941 // Inserting the gropuing operator afterwards is easier.
942 if (groupingUsed)
943 mainPattern.insert(mainPattern.length() - groupingSize,
944 syms.getGroupingSeparator());
945 // See if we need decimal info.
946 if (minimumFractionDigits > 0 || maximumFractionDigits > 0
947 || decimalSeparatorAlwaysShown)
948 mainPattern.append(syms.getDecimalSeparator());
949 for (int i = 0; i < minimumFractionDigits; ++i)
950 mainPattern.append(syms.getZeroDigit());
951 for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
952 mainPattern.append(syms.getDigit());
953 if (useExponentialNotation)
954 {
955 mainPattern.append(syms.getExponential());
956 for (int i = 0; i < minExponentDigits; ++i)
957 mainPattern.append(syms.getZeroDigit());
958 if (minExponentDigits == 0)
959 mainPattern.append(syms.getDigit());
960 }
961
962 String main = mainPattern.toString();
963 String patChars = patternChars (syms);
964 mainPattern.setLength(0);
965
966 quoteFix (mainPattern, positivePrefix, patChars);
967 mainPattern.append(main);
968 quoteFix (mainPattern, positiveSuffix, patChars);
969
970 if (negativePrefix != null)
971 {
972 quoteFix (mainPattern, negativePrefix, patChars);
973 mainPattern.append(main);
974 quoteFix (mainPattern, negativeSuffix, patChars);
975 }
976
977 return mainPattern.toString();
978 }
979
980 public String toLocalizedPattern ()
981 {
982 return computePattern (symbols);
983 }
984
985 public String toPattern ()
986 {
987 return computePattern (nonLocalizedSymbols);
988 }
989
990 // These names are fixed by the serialization spec.
991 private boolean decimalSeparatorAlwaysShown;
992 private byte groupingSize;
993 private byte minExponentDigits;
994 private int multiplier;
995 private String negativePrefix;
996 private String negativeSuffix;
997 private String positivePrefix;
998 private String positiveSuffix;
999 private int serialVersionOnStream = 1;
1000 private DecimalFormatSymbols symbols;
1001 private boolean useExponentialNotation;
1002 private static final long serialVersionUID = 864413376551465018L;
1003
1004 private void readObject(ObjectInputStream stream)
1005 throws IOException, ClassNotFoundException
1006 {
1007 stream.defaultReadObject();
1008 if (serialVersionOnStream < 1)
1009 {
1010 useExponentialNotation = false;
1011 serialVersionOnStream = 1;
1012 }
1013 }
1014
1015 // The locale-independent pattern symbols happen to be the same as
1016 // the US symbols.
1017 private static final DecimalFormatSymbols nonLocalizedSymbols
1018 = new DecimalFormatSymbols (Locale.US);
1019}
Note: See TracBrowser for help on using the repository browser.