1:
37:
38:
43:
44: package ;
45:
46: import ;
47: import ;
48:
49: import ;
50: import ;
51: import ;
52:
53:
67:
68:
78: public class DecimalFormat extends NumberFormat
79: {
80:
81: private static final long serialVersionUID = 864413376551465018L;
82:
83:
84: private static final int DEFAULT_INTEGER_DIGITS = 309;
85:
86:
90: private static final int DEFAULT_FRACTION_DIGITS = 340;
91:
92:
95:
96: private static final DecimalFormatSymbols nonLocalizedSymbols
97: = new DecimalFormatSymbols (Locale.US);
98:
99:
102: private boolean parseBigDecimal;
103:
104:
108: private boolean useCurrencySeparator;
109:
110:
111: private boolean decimalSeparatorAlwaysShown;
112:
113:
119: private boolean showDecimalSeparator;
120:
121:
126: private boolean groupingSeparatorInPattern;
127:
128:
129: private byte groupingSize;
130:
131:
136: private byte minExponentDigits;
137:
138:
139: private int exponentRound;
140:
141:
142: private int multiplier;
143:
144:
145: private int negativePatternMultiplier;
146:
147:
148: private String negativePrefix;
149:
150:
151: private String negativeSuffix;
152:
153:
154: private String positivePrefix;
155:
156:
157: private String positiveSuffix;
158:
159:
160: private DecimalFormatSymbols symbols;
161:
162:
163: private boolean useExponentialNotation;
164:
165:
169: private int maxIntegerDigitsExponent;
170:
171:
172: private boolean hasNegativePrefix;
173:
174:
175: private boolean hasFractionalPattern;
176:
177:
178: private ArrayList attributes = new ArrayList();
179:
180:
184: public DecimalFormat()
185: {
186: this ("#,##0.###");
187: }
188:
189:
197: public DecimalFormat(String pattern)
198: {
199: this (pattern, new DecimalFormatSymbols());
200: }
201:
202:
212: public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
213: {
214: this.symbols = (DecimalFormatSymbols) symbols.clone();
215: applyPatternWithSymbols(pattern, nonLocalizedSymbols);
216: }
217:
218:
225: public void applyLocalizedPattern (String pattern)
226: {
227: applyPatternWithSymbols(pattern, this.symbols);
228: }
229:
230:
237: public void applyPattern(String pattern)
238: {
239: applyPatternWithSymbols(pattern, nonLocalizedSymbols);
240: }
241:
242: public Object clone()
243: {
244: DecimalFormat c = (DecimalFormat) super.clone();
245: c.symbols = (DecimalFormatSymbols) symbols.clone();
246: return c;
247: }
248:
249:
262: public boolean equals(Object obj)
263: {
264: if (! (obj instanceof DecimalFormat))
265: return false;
266: DecimalFormat dup = (DecimalFormat) obj;
267: return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
268: && groupingUsed == dup.groupingUsed
269: && groupingSeparatorInPattern == dup.groupingSeparatorInPattern
270: && groupingSize == dup.groupingSize
271: && multiplier == dup.multiplier
272: && useExponentialNotation == dup.useExponentialNotation
273: && minExponentDigits == dup.minExponentDigits
274: && minimumIntegerDigits == dup.minimumIntegerDigits
275: && maximumIntegerDigits == dup.maximumIntegerDigits
276: && minimumFractionDigits == dup.minimumFractionDigits
277: && maximumFractionDigits == dup.maximumFractionDigits
278: && parseBigDecimal == dup.parseBigDecimal
279: && useCurrencySeparator == dup.useCurrencySeparator
280: && showDecimalSeparator == dup.showDecimalSeparator
281: && exponentRound == dup.exponentRound
282: && negativePatternMultiplier == dup.negativePatternMultiplier
283: && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent
284:
285:
286: && equals(negativePrefix, dup.negativePrefix)
287: && equals(negativeSuffix, dup.negativeSuffix)
288: && equals(positivePrefix, dup.positivePrefix)
289: && equals(positiveSuffix, dup.positiveSuffix)
290: && symbols.equals(dup.symbols));
291: }
292:
293:
298: public int hashCode()
299: {
300: return toPattern().hashCode();
301: }
302:
303:
313: public StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos)
314: {
315: if (obj instanceof BigInteger)
316: {
317: BigDecimal decimal = new BigDecimal((BigInteger) obj);
318: formatInternal(decimal, true, sbuf, pos);
319: return sbuf;
320: }
321: else if (obj instanceof BigDecimal)
322: {
323: formatInternal((BigDecimal) obj, true, sbuf, pos);
324: return sbuf;
325: }
326:
327: return super.format(obj, sbuf, pos);
328: }
329:
330:
340: public StringBuffer format(double number, StringBuffer dest,
341: FieldPosition fieldPos)
342: {
343:
344: if (Double.isNaN(number))
345: {
346:
347: String nan = symbols.getNaN();
348: dest.append(nan);
349:
350:
351: if ((fieldPos.getField() == INTEGER_FIELD ||
352: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
353: {
354: int index = dest.length();
355: fieldPos.setBeginIndex(index - nan.length());
356: fieldPos.setEndIndex(index);
357: }
358: }
359: else if (Double.isInfinite(number))
360: {
361:
362: if (number < 0)
363: dest.append(this.negativePrefix);
364: else
365: dest.append(this.positivePrefix);
366:
367: dest.append(symbols.getInfinity());
368:
369: if (number < 0)
370: dest.append(this.negativeSuffix);
371: else
372: dest.append(this.positiveSuffix);
373:
374: if ((fieldPos.getField() == INTEGER_FIELD ||
375: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
376: {
377: fieldPos.setBeginIndex(dest.length());
378: fieldPos.setEndIndex(0);
379: }
380: }
381: else
382: {
383:
384: BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
385: formatInternal(bigDecimal, false, dest, fieldPos);
386: }
387:
388: return dest;
389: }
390:
391:
400: public StringBuffer format(long number, StringBuffer dest,
401: FieldPosition fieldPos)
402: {
403: BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
404: formatInternal(bigDecimal, true, dest, fieldPos);
405: return dest;
406: }
407:
408:
417: public AttributedCharacterIterator formatToCharacterIterator(Object value)
418: {
419:
423:
424: if (value == null)
425: throw new NullPointerException("Passed Object is null");
426:
427: if (!(value instanceof Number)) throw new
428: IllegalArgumentException("Cannot format given Object as a Number");
429:
430: StringBuffer text = new StringBuffer();
431: attributes.clear();
432: super.format(value, text, new FieldPosition(0));
433:
434: AttributedString as = new AttributedString(text.toString());
435:
436:
437: for (int i = 0; i < attributes.size(); i++)
438: {
439: FieldPosition pos = (FieldPosition) attributes.get(i);
440: Format.Field attribute = pos.getFieldAttribute();
441:
442: as.addAttribute(attribute, attribute, pos.getBeginIndex(),
443: pos.getEndIndex());
444: }
445:
446:
447: return as.getIterator();
448: }
449:
450:
458: public Currency getCurrency()
459: {
460: return symbols.getCurrency();
461: }
462:
463:
468: public DecimalFormatSymbols getDecimalFormatSymbols()
469: {
470: return (DecimalFormatSymbols) symbols.clone();
471: }
472:
473:
483: public int getGroupingSize()
484: {
485: return groupingSize;
486: }
487:
488:
493: public int getMultiplier()
494: {
495: return multiplier;
496: }
497:
498:
503: public String getNegativePrefix()
504: {
505: return negativePrefix;
506: }
507:
508:
513: public String getNegativeSuffix()
514: {
515: return negativeSuffix;
516: }
517:
518:
523: public String getPositivePrefix()
524: {
525: return positivePrefix;
526: }
527:
528:
533: public String getPositiveSuffix()
534: {
535: return positiveSuffix;
536: }
537:
538: public boolean isDecimalSeparatorAlwaysShown()
539: {
540: return decimalSeparatorAlwaysShown;
541: }
542:
543:
549: public void setParseBigDecimal(boolean newValue)
550: {
551: this.parseBigDecimal = newValue;
552: }
553:
554:
565: public boolean isParseBigDecimal()
566: {
567: return this.parseBigDecimal;
568: }
569:
570:
583: public Number parse(String str, ParsePosition pos)
584: {
585:
586:
587: if (str.contains(this.symbols.getNaN()))
588: return Double.valueOf(Double.NaN);
589:
590:
591: StringBuffer number = new StringBuffer();
592:
593:
594: char minus = symbols.getMinusSign();
595:
596:
597: int start = pos.getIndex();
598:
599:
600:
601: String _negativePrefix = (this.negativePrefix.compareTo("") == 0
602: ? minus + positivePrefix
603: : this.negativePrefix);
604:
605:
606:
607: int positiveLen = positivePrefix.length();
608: int negativeLen = _negativePrefix.length();
609:
610: boolean isNegative = str.startsWith(_negativePrefix);
611: boolean isPositive = str.startsWith(positivePrefix);
612:
613: if (isPositive && isNegative)
614: {
615:
616:
617: if (negativeLen > positiveLen)
618: {
619: start += _negativePrefix.length();
620: isNegative = true;
621: }
622: else
623: {
624: start += positivePrefix.length();
625: isPositive = true;
626: if (negativeLen < positiveLen)
627: isNegative = false;
628: }
629: }
630: else if (isNegative)
631: {
632: start += _negativePrefix.length();
633: isPositive = false;
634: }
635: else if (isPositive)
636: {
637: start += positivePrefix.length();
638: isNegative = false;
639: }
640: else
641: {
642: pos.setErrorIndex(start);
643: return null;
644: }
645:
646:
647: char decimalSeparator = symbols.getDecimalSeparator();
648: char zero = symbols.getZeroDigit();
649: char exponent = symbols.getExponential();
650:
651:
652: int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2;
653:
654: if (useExponentialNotation)
655: stop += minExponentDigits + 1;
656:
657: boolean inExponent = false;
658:
659:
660: int len = str.length();
661: if (len < stop) stop = len;
662: char groupingSeparator = symbols.getGroupingSeparator();
663:
664: int i = start;
665: while (i < stop)
666: {
667: char ch = str.charAt(i);
668: i++;
669:
670: if (ch >= zero && ch <= (zero + 9))
671: {
672: number.append(ch);
673: }
674: else if (this.parseIntegerOnly)
675: {
676: i--;
677: break;
678: }
679: else if (ch == decimalSeparator)
680: {
681: number.append('.');
682: }
683: else if (ch == exponent)
684: {
685: number.append(ch);
686: inExponent = !inExponent;
687: }
688: else if ((ch == '+' || ch == '-' || ch == minus))
689: {
690: if (inExponent)
691: number.append(ch);
692: else
693: {
694: i--;
695: break;
696: }
697: }
698: else
699: {
700: if (!groupingUsed || ch != groupingSeparator)
701: {
702: i--;
703: break;
704: }
705: }
706: }
707:
708:
709:
710: if (str.contains(symbols.getInfinity()))
711: {
712: int inf = str.indexOf(symbols.getInfinity());
713: pos.setIndex(inf);
714:
715:
716: if (this.parseBigDecimal)
717: {
718: if (isNegative)
719: return new BigDecimal(Double.NEGATIVE_INFINITY);
720:
721: return new BigDecimal(Double.POSITIVE_INFINITY);
722: }
723:
724: if (isNegative)
725: return new Double(Double.NEGATIVE_INFINITY);
726:
727: return new Double(Double.POSITIVE_INFINITY);
728: }
729:
730:
731: if (i == start || number.length() == 0)
732: {
733: pos.setErrorIndex(i);
734: return null;
735: }
736:
737:
738:
739: boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
740: boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
741: boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
742:
743: positiveLen = positiveSuffix.length();
744: negativeLen = negativeSuffix.length();
745:
746: if (isNegative && !hasNegativeSuffix)
747: {
748: pos.setErrorIndex(i);
749: return null;
750: }
751: else if (hasNegativeSuffix &&
752: !positiveEqualsNegative &&
753: (negativeLen > positiveLen))
754: {
755: isNegative = true;
756: }
757: else if (!hasPositiveSuffix)
758: {
759: pos.setErrorIndex(i);
760: return null;
761: }
762:
763: if (isNegative) number.insert(0, '-');
764:
765: pos.setIndex(i);
766:
767:
768: BigDecimal bigDecimal = new BigDecimal(number.toString());
769: if (this.parseBigDecimal)
770: return bigDecimal;
771:
772:
773: if (this.parseIntegerOnly)
774: return new Long(bigDecimal.longValue());
775:
776:
777: if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0))
778: return new Double(-0.0);
779:
780: try
781: {
782: BigDecimal integer
783: = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY);
784: return new Long(integer.longValue());
785: }
786: catch (ArithmeticException e)
787: {
788: return new Double(bigDecimal.doubleValue());
789: }
790: }
791:
792:
800: public void setCurrency(Currency currency)
801: {
802: symbols.setCurrency(currency);
803: }
804:
805:
811: public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
812: {
813: symbols = (DecimalFormatSymbols) newSymbols.clone();
814: }
815:
816:
825: public void setDecimalSeparatorAlwaysShown(boolean newValue)
826: {
827: decimalSeparatorAlwaysShown = newValue;
828: }
829:
830:
838: public void setGroupingSize(int groupSize)
839: {
840: groupingSize = (byte) groupSize;
841: }
842:
843:
852: public void setMaximumIntegerDigits(int newValue)
853: {
854: newValue = (newValue > 0) ? newValue : 0;
855: super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
856: }
857:
858:
867: public void setMinimumIntegerDigits(int newValue)
868: {
869: newValue = (newValue > 0) ? newValue : 0;
870: super.setMinimumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
871: }
872:
873:
882: public void setMaximumFractionDigits(int newValue)
883: {
884: newValue = (newValue > 0) ? newValue : 0;
885: super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
886: }
887:
888:
897: public void setMinimumFractionDigits(int newValue)
898: {
899: newValue = (newValue > 0) ? newValue : 0;
900: super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
901: }
902:
903:
910: public void setMultiplier(int newValue)
911: {
912: multiplier = newValue;
913: }
914:
915:
920: public void setNegativePrefix(String newValue)
921: {
922: negativePrefix = newValue;
923: }
924:
925:
930: public void setNegativeSuffix(String newValue)
931: {
932: negativeSuffix = newValue;
933: }
934:
935:
940: public void setPositivePrefix(String newValue)
941: {
942: positivePrefix = newValue;
943: }
944:
945:
950: public void setPositiveSuffix(String newValue)
951: {
952: positiveSuffix = newValue;
953: }
954:
955:
962: public String toLocalizedPattern()
963: {
964: return computePattern(this.symbols);
965: }
966:
967:
974: public String toPattern()
975: {
976: return computePattern(nonLocalizedSymbols);
977: }
978:
979:
980:
981:
990: private boolean equals(String s1, String s2)
991: {
992: if (s1 == null || s2 == null)
993: return s1 == s2;
994: return s1.equals(s2);
995: }
996:
997:
998:
999:
1000:
1004: private String patternChars (DecimalFormatSymbols syms)
1005: {
1006: StringBuffer buf = new StringBuffer ();
1007:
1008: buf.append(syms.getDecimalSeparator());
1009: buf.append(syms.getDigit());
1010: buf.append(syms.getExponential());
1011: buf.append(syms.getGroupingSeparator());
1012: buf.append(syms.getMinusSign());
1013: buf.append(syms.getPatternSeparator());
1014: buf.append(syms.getPercent());
1015: buf.append(syms.getPerMill());
1016: buf.append(syms.getZeroDigit());
1017: buf.append('\'');
1018: buf.append('\u00a4');
1019:
1020: return buf.toString();
1021: }
1022:
1023:
1031: private StringBuffer quoteFix(String text, String patChars)
1032: {
1033: StringBuffer buf = new StringBuffer();
1034:
1035: int len = text.length();
1036: char ch;
1037: for (int index = 0; index < len; ++index)
1038: {
1039: ch = text.charAt(index);
1040: if (patChars.indexOf(ch) != -1)
1041: {
1042: buf.append('\'');
1043: buf.append(ch);
1044: if (ch != '\'') buf.append('\'');
1045: }
1046: else
1047: {
1048: buf.append(ch);
1049: }
1050: }
1051:
1052: return buf;
1053: }
1054:
1055:
1059: private String computePattern(DecimalFormatSymbols symbols)
1060: {
1061: StringBuffer mainPattern = new StringBuffer();
1062:
1063:
1064:
1065:
1066: int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize;
1067: int totalDigits = Math.max(minimumIntegerDigits, _groupingSize);
1068:
1069:
1070:
1071: if (!useExponentialNotation) mainPattern.append(symbols.getDigit());
1072:
1073: for (int i = 1; i < totalDigits - minimumIntegerDigits; i++)
1074: mainPattern.append(symbols.getDigit());
1075:
1076: for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++)
1077: mainPattern.append(symbols.getZeroDigit());
1078:
1079: if (groupingUsed)
1080: {
1081: mainPattern.insert(mainPattern.length() - groupingSize,
1082: symbols.getGroupingSeparator());
1083: }
1084:
1085:
1086: if (minimumFractionDigits > 0 || maximumFractionDigits > 0 ||
1087: decimalSeparatorAlwaysShown)
1088: {
1089: mainPattern.append(symbols.getDecimalSeparator());
1090: }
1091:
1092: for (int i = 0; i < minimumFractionDigits; ++i)
1093: mainPattern.append(symbols.getZeroDigit());
1094:
1095: for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
1096: mainPattern.append(symbols.getDigit());
1097:
1098: if (useExponentialNotation)
1099: {
1100: mainPattern.append(symbols.getExponential());
1101:
1102: for (int i = 0; i < minExponentDigits; ++i)
1103: mainPattern.append(symbols.getZeroDigit());
1104:
1105: if (minExponentDigits == 0)
1106: mainPattern.append(symbols.getDigit());
1107: }
1108:
1109:
1110: String pattern = mainPattern.toString();
1111:
1112:
1113:
1114: String patternChars = patternChars(symbols);
1115: mainPattern.insert(0, quoteFix(positivePrefix, patternChars));
1116: mainPattern.append(quoteFix(positiveSuffix, patternChars));
1117:
1118: if (hasNegativePrefix)
1119: {
1120: mainPattern.append(symbols.getPatternSeparator());
1121: mainPattern.append(quoteFix(negativePrefix, patternChars));
1122: mainPattern.append(pattern);
1123: mainPattern.append(quoteFix(negativeSuffix, patternChars));
1124: }
1125:
1126:
1127: return mainPattern.toString();
1128: }
1129:
1130:
1131:
1132:
1139: private void applyPatternWithSymbols(String pattern,
1140: DecimalFormatSymbols symbols)
1141: {
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156: setDefaultValues();
1157:
1158: int len = pattern.length();
1159: if (len == 0)
1160: {
1161:
1162: this.minimumIntegerDigits = 1;
1163: this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
1164: this.minimumFractionDigits = 0;
1165: this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
1166:
1167:
1168: this.minExponentDigits = 0;
1169: this.showDecimalSeparator = true;
1170: this.groupingUsed = true;
1171: this.groupingSize = 3;
1172:
1173: return;
1174: }
1175:
1176: int start = scanFix(pattern, symbols, 0, true);
1177: if (start < len) start = scanNumberInteger(pattern, symbols, start);
1178: if (start < len)
1179: {
1180: start = scanFractionalPortion(pattern, symbols, start);
1181: }
1182: else
1183: {
1184:
1185:
1186: this.minimumFractionDigits = 0;
1187: this.maximumFractionDigits = 0;
1188:
1189:
1190: }
1191:
1192:
1193:
1194:
1195:
1196:
1197: if (start < len) start = scanExponent(pattern, symbols, start);
1198: if (start < len) start = scanFix(pattern, symbols, start, false);
1199: if (start < len) scanNegativePattern(pattern, symbols, start);
1200:
1201: if (useExponentialNotation &&
1202: (maxIntegerDigitsExponent > minimumIntegerDigits) &&
1203: (maxIntegerDigitsExponent > 1))
1204: {
1205: minimumIntegerDigits = 1;
1206: exponentRound = maxIntegerDigitsExponent;
1207: }
1208:
1209: if (useExponentialNotation)
1210: maximumIntegerDigits = maxIntegerDigitsExponent;
1211:
1212: if (!this.hasFractionalPattern && this.showDecimalSeparator == true)
1213: {
1214: this.decimalSeparatorAlwaysShown = true;
1215: }
1216: }
1217:
1218:
1225: private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols,
1226: int start, boolean prefix)
1227: {
1228: StringBuffer buffer = new StringBuffer();
1229:
1230:
1231:
1232: char decimalSeparator = sourceSymbols.getDecimalSeparator();
1233: char patternSeparator = sourceSymbols.getPatternSeparator();
1234: char groupingSeparator = sourceSymbols.getGroupingSeparator();
1235: char digit = sourceSymbols.getDigit();
1236: char zero = sourceSymbols.getZeroDigit();
1237: char minus = sourceSymbols.getMinusSign();
1238:
1239:
1240: char percent = sourceSymbols.getPercent();
1241: char permille = sourceSymbols.getPerMill();
1242:
1243: String currencySymbol = this.symbols.getCurrencySymbol();
1244:
1245: boolean quote = false;
1246:
1247: char ch = pattern.charAt(start);
1248: if (ch == patternSeparator)
1249: {
1250:
1251: this.hasNegativePrefix = true;
1252: ++start;
1253: return start;
1254: }
1255:
1256: int len = pattern.length();
1257: int i;
1258: for (i = start; i < len; i++)
1259: {
1260: ch = pattern.charAt(i);
1261:
1262:
1263: if (!quote && ch == patternSeparator)
1264: {
1265: if (this.hasNegativePrefix)
1266: {
1267: throw new IllegalArgumentException("Invalid pattern found: "
1268: + start);
1269: }
1270:
1271: this.hasNegativePrefix = true;
1272: ++i;
1273: break;
1274: }
1275:
1276:
1277: if (!quote &&
1278: (ch == minus || ch == digit || ch == zero ||
1279: ch == groupingSeparator))
1280: break;
1281:
1282: if (!quote && ch == decimalSeparator)
1283: {
1284: this.showDecimalSeparator = true;
1285: break;
1286: }
1287: else if (quote && ch != '\'')
1288: {
1289: buffer.append(ch);
1290: continue;
1291: }
1292:
1293: if (ch == '\u00A4')
1294: {
1295:
1296: currencySymbol = this.symbols.getCurrencySymbol();
1297:
1298:
1299: if (i < len && pattern.charAt(i + 1) == '\u00A4')
1300: {
1301: currencySymbol = this.symbols.getInternationalCurrencySymbol();
1302: i++;
1303: }
1304:
1305: this.useCurrencySeparator = true;
1306: buffer.append(currencySymbol);
1307: }
1308: else if (ch == percent)
1309: {
1310:
1311: this.multiplier = 100;
1312: buffer.append(this.symbols.getPercent());
1313: }
1314: else if (ch == permille)
1315: {
1316:
1317: this.multiplier = 1000;
1318: buffer.append(this.symbols.getPerMill());
1319: }
1320: else if (ch == '\'')
1321: {
1322:
1323: if (i < len && pattern.charAt(i + 1) == '\'')
1324: {
1325:
1326: buffer.append(ch);
1327: i++;
1328: }
1329: else
1330: {
1331: quote = !quote;
1332: continue;
1333: }
1334: }
1335: else
1336: {
1337: buffer.append(ch);
1338: }
1339: }
1340:
1341: if (prefix)
1342: {
1343: this.positivePrefix = buffer.toString();
1344: this.negativePrefix = minus + "" + positivePrefix;
1345: }
1346: else
1347: {
1348: this.positiveSuffix = buffer.toString();
1349: }
1350:
1351: return i;
1352: }
1353:
1354:
1364: private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols,
1365: int start)
1366: {
1367: char digit = symbols.getDigit();
1368: char zero = symbols.getZeroDigit();
1369: char groupingSeparator = symbols.getGroupingSeparator();
1370: char decimalSeparator = symbols.getDecimalSeparator();
1371: char exponent = symbols.getExponential();
1372: char patternSeparator = symbols.getPatternSeparator();
1373:
1374:
1375:
1376: int zeros = 0;
1377:
1378:
1379: int _groupingSize = 0;
1380:
1381: this.maxIntegerDigitsExponent = 0;
1382:
1383: boolean intPartTouched = false;
1384:
1385: char ch;
1386: int len = pattern.length();
1387: int i;
1388: for (i = start; i < len; i++)
1389: {
1390: ch = pattern.charAt(i);
1391:
1392:
1393: if (ch == decimalSeparator || ch == exponent)
1394: break;
1395:
1396: if (this.hasNegativePrefix && ch == patternSeparator)
1397: throw new IllegalArgumentException("Invalid pattern found: "
1398: + start);
1399:
1400: if (ch == digit)
1401: {
1402:
1403:
1404:
1405: if (zeros > 0) throw new
1406: IllegalArgumentException("digit mark following zero in " +
1407: "positive subpattern, not allowed. Position: " + i);
1408:
1409: _groupingSize++;
1410: intPartTouched = true;
1411: this.maxIntegerDigitsExponent++;
1412: }
1413: else if (ch == zero)
1414: {
1415: zeros++;
1416: _groupingSize++;
1417: this.maxIntegerDigitsExponent++;
1418: }
1419: else if (ch == groupingSeparator)
1420: {
1421: this.groupingSeparatorInPattern = true;
1422: this.groupingUsed = true;
1423: _groupingSize = 0;
1424: }
1425: else
1426: {
1427:
1428:
1429: break;
1430: }
1431: }
1432:
1433: if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize;
1434: this.minimumIntegerDigits = zeros;
1435:
1436:
1437:
1438: if (intPartTouched && this.maximumIntegerDigits > 0 &&
1439: this.minimumIntegerDigits == 0)
1440: this.minimumIntegerDigits = 1;
1441:
1442: return i;
1443: }
1444:
1445:
1455: private int scanFractionalPortion(String pattern,
1456: DecimalFormatSymbols symbols,
1457: int start)
1458: {
1459: char digit = symbols.getDigit();
1460: char zero = symbols.getZeroDigit();
1461: char groupingSeparator = symbols.getGroupingSeparator();
1462: char decimalSeparator = symbols.getDecimalSeparator();
1463: char exponent = symbols.getExponential();
1464: char patternSeparator = symbols.getPatternSeparator();
1465:
1466:
1467:
1468: char ch = pattern.charAt(start);
1469: if (ch != decimalSeparator)
1470: {
1471: this.minimumFractionDigits = 0;
1472: this.maximumFractionDigits = 0;
1473: return start;
1474: }
1475:
1476: ++start;
1477:
1478: this.hasFractionalPattern = true;
1479:
1480: this.minimumFractionDigits = 0;
1481: int digits = 0;
1482:
1483: int len = pattern.length();
1484: int i;
1485: for (i = start; i < len; i++)
1486: {
1487: ch = pattern.charAt(i);
1488:
1489:
1490: if (ch == exponent || ch == patternSeparator)
1491: break;
1492:
1493:
1494: if (ch == groupingSeparator || ch == decimalSeparator) throw new
1495: IllegalArgumentException("unexpected character '" + ch + "' " +
1496: "in fractional subpattern. Position: " + i);
1497:
1498: if (ch == digit)
1499: {
1500: digits++;
1501: }
1502: else if (ch == zero)
1503: {
1504: if (digits > 0) throw new
1505: IllegalArgumentException("digit mark following zero in " +
1506: "positive subpattern, not allowed. Position: " + i);
1507:
1508: this.minimumFractionDigits++;
1509: }
1510: else
1511: {
1512:
1513: break;
1514: }
1515: }
1516:
1517: if (i == start) this.hasFractionalPattern = false;
1518:
1519: this.maximumFractionDigits = this.minimumFractionDigits + digits;
1520: this.showDecimalSeparator = true;
1521:
1522: return i;
1523: }
1524:
1525:
1535: private int scanExponent(String pattern, DecimalFormatSymbols symbols,
1536: int start)
1537: {
1538: char digit = symbols.getDigit();
1539: char zero = symbols.getZeroDigit();
1540: char groupingSeparator = symbols.getGroupingSeparator();
1541: char decimalSeparator = symbols.getDecimalSeparator();
1542: char exponent = symbols.getExponential();
1543:
1544: char ch = pattern.charAt(start);
1545:
1546: if (ch == decimalSeparator)
1547: {
1548:
1549: ++start;
1550: }
1551:
1552: if (ch != exponent)
1553: {
1554: this.useExponentialNotation = false;
1555: return start;
1556: }
1557:
1558: ++start;
1559:
1560: this.minExponentDigits = 0;
1561:
1562: int len = pattern.length();
1563: int i;
1564: for (i = start; i < len; i++)
1565: {
1566: ch = pattern.charAt(i);
1567:
1568: if (ch == groupingSeparator || ch == decimalSeparator ||
1569: ch == digit || ch == exponent) throw new
1570: IllegalArgumentException("unexpected character '" + ch + "' " +
1571: "in exponential subpattern. Position: " + i);
1572:
1573: if (ch == zero)
1574: {
1575: this.minExponentDigits++;
1576: }
1577: else
1578: {
1579:
1580: break;
1581: }
1582: }
1583:
1584: this.useExponentialNotation = true;
1585:
1586: return i;
1587: }
1588:
1589:
1598: private void scanNegativePattern(String pattern,
1599: DecimalFormatSymbols sourceSymbols,
1600: int start)
1601: {
1602: StringBuffer buffer = new StringBuffer();
1603:
1604:
1605:
1606: char decimalSeparator = sourceSymbols.getDecimalSeparator();
1607: char patternSeparator = sourceSymbols.getPatternSeparator();
1608: char groupingSeparator = sourceSymbols.getGroupingSeparator();
1609: char digit = sourceSymbols.getDigit();
1610: char zero = sourceSymbols.getZeroDigit();
1611: char minus = sourceSymbols.getMinusSign();
1612:
1613:
1614: char percent = sourceSymbols.getPercent();
1615: char permille = sourceSymbols.getPerMill();
1616:
1617: String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol();
1618: String currencySymbol = CURRENCY_SYMBOL;
1619:
1620: boolean quote = false;
1621: boolean prefixDone = false;
1622:
1623: int len = pattern.length();
1624: if (len > 0) this.hasNegativePrefix = true;
1625:
1626: char ch = pattern.charAt(start);
1627: if (ch == patternSeparator)
1628: {
1629:
1630: if ((start + 1) > len) throw new
1631: IllegalArgumentException("unexpected character '" + ch + "' " +
1632: "in negative subpattern.");
1633: start++;
1634: }
1635:
1636: int i;
1637: for (i = start; i < len; i++)
1638: {
1639: ch = pattern.charAt(i);
1640:
1641:
1642: if (!quote &&
1643: (ch == digit || ch == zero || ch == decimalSeparator ||
1644: ch == patternSeparator || ch == groupingSeparator))
1645: {
1646: if (!prefixDone)
1647: {
1648: this.negativePrefix = buffer.toString();
1649: buffer.delete(0, buffer.length());
1650: prefixDone = true;
1651: }
1652: }
1653: else if (ch == minus)
1654: {
1655: buffer.append(this.symbols.getMinusSign());
1656: }
1657: else if (quote && ch != '\'')
1658: {
1659: buffer.append(ch);
1660: }
1661: else if (ch == '\u00A4')
1662: {
1663:
1664: currencySymbol = CURRENCY_SYMBOL;
1665:
1666:
1667: if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
1668: {
1669: currencySymbol = this.symbols.getInternationalCurrencySymbol();
1670: i = i + 2;
1671: }
1672:
1673:
1674:
1675:
1676:
1677:
1678: buffer.append(currencySymbol);
1679: }
1680: else if (ch == percent)
1681: {
1682:
1683: this.negativePatternMultiplier = 100;
1684: buffer.append(this.symbols.getPercent());
1685: }
1686: else if (ch == permille)
1687: {
1688:
1689: this.negativePatternMultiplier = 1000;
1690: buffer.append(this.symbols.getPerMill());
1691: }
1692: else if (ch == '\'')
1693: {
1694:
1695: if (i < len && pattern.charAt(i + 1) == '\'')
1696: {
1697:
1698: buffer.append(ch);
1699: i++;
1700: }
1701: else
1702: {
1703: quote = !quote;
1704: }
1705: }
1706: else if (ch == patternSeparator)
1707: {
1708:
1709: throw new IllegalArgumentException("unexpected character '" + ch +
1710: "' in negative subpattern.");
1711: }
1712: else
1713: {
1714: buffer.append(ch);
1715: }
1716: }
1717:
1718: if (prefixDone)
1719: this.negativeSuffix = buffer.toString();
1720: else
1721: this.negativePrefix = buffer.toString();
1722: }
1723:
1724:
1725:
1726:
1742: private void formatInternal(BigDecimal number, boolean isLong,
1743: StringBuffer dest, FieldPosition fieldPos)
1744: {
1745:
1746:
1747:
1748:
1749:
1750:
1751:
1752: if (fieldPos == null) fieldPos = new FieldPosition(0);
1753:
1754: int _multiplier = this.multiplier;
1755:
1756:
1757: int attributeStart = -1;
1758:
1759:
1760:
1761: boolean isNegative = (number.signum() < 0) ? true : false;
1762: if (isNegative)
1763: {
1764: attributeStart = dest.length();
1765:
1766:
1767: dest.append(negativePrefix);
1768:
1769:
1770:
1771: number = number.abs();
1772:
1773: _multiplier = negativePatternMultiplier;
1774:
1775: addAttribute(Field.SIGN, attributeStart, dest.length());
1776: }
1777: else
1778: {
1779:
1780: dest.append(positivePrefix);
1781: }
1782:
1783:
1784: int beginIndexInt = dest.length();
1785: int endIndexInt = 0;
1786: int beginIndexFract = 0;
1787: int endIndexFract = 0;
1788:
1789:
1790: number = number.multiply(new BigDecimal(_multiplier));
1791:
1792:
1793:
1794:
1795: if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0)
1796: {
1797: number = BigDecimal.ZERO;
1798: this.maximumIntegerDigits = 1;
1799: this.minimumIntegerDigits = 1;
1800: }
1801:
1802:
1803: number = number.abs();
1804:
1805:
1806: int scale = this.maximumFractionDigits;
1807:
1808:
1809:
1810:
1811: long exponent = 0;
1812:
1813:
1814: if (this.useExponentialNotation)
1815: {
1816: exponent = getExponent(number);
1817: number = number.movePointLeft((int) exponent);
1818:
1819:
1820:
1821:
1822:
1823:
1824: }
1825:
1826:
1827: number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
1828:
1829:
1830:
1831: String plain = number.toPlainString();
1832:
1833: String intPart = null;
1834: String fractPart = null;
1835:
1836:
1837:
1838:
1839: int minusIndex = plain.lastIndexOf('-', 0);
1840: if (minusIndex > -1) plain = plain.substring(minusIndex + 1);
1841:
1842:
1843: int dot = plain.indexOf('.');
1844: if (dot > -1)
1845: {
1846: intPart = plain.substring(0, dot);
1847: dot++;
1848:
1849: if (useExponentialNotation)
1850: fractPart = plain.substring(dot, dot + scale);
1851: else
1852: fractPart = plain.substring(dot);
1853: }
1854: else
1855: {
1856: intPart = plain;
1857: }
1858:
1859:
1860: int intPartLen = intPart.length();
1861: endIndexInt = intPartLen;
1862:
1863:
1864:
1865:
1866: int zeroes = minimumIntegerDigits - intPartLen;
1867: if (zeroes > 0)
1868: {
1869: attributeStart = Math.max(dest.length() - 1, 0);
1870: appendZero(dest, zeroes, minimumIntegerDigits);
1871: }
1872:
1873: if (this.useExponentialNotation)
1874: {
1875:
1876:
1877:
1878:
1879:
1880: if (attributeStart < 0)
1881: attributeStart = Math.max(dest.length() - 1, 0);
1882: appendDigit(intPart, dest, this.groupingUsed);
1883: }
1884: else
1885: {
1886:
1887: intPartLen = intPart.length();
1888: int canary = Math.min(intPartLen, this.maximumIntegerDigits);
1889:
1890:
1891:
1892: intPart = intPart.substring(intPartLen - canary);
1893: endIndexInt = intPart.length() + 1;
1894:
1895:
1896: if (maximumIntegerDigits > 0 &&
1897: !(this.minimumIntegerDigits == 0 &&
1898: intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0))
1899: {
1900: if (attributeStart < 0)
1901: attributeStart = Math.max(dest.length() - 1, 0);
1902: appendDigit(intPart, dest, this.groupingUsed);
1903: }
1904: }
1905:
1906:
1907: addAttribute(Field.INTEGER, attributeStart, dest.length());
1908:
1909:
1910: if ((fieldPos.getField() == INTEGER_FIELD ||
1911: fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
1912: {
1913: fieldPos.setBeginIndex(beginIndexInt);
1914: fieldPos.setEndIndex(endIndexInt);
1915: }
1916:
1917: handleFractionalPart(dest, fractPart, fieldPos, isLong);
1918:
1919:
1920: if (this.useExponentialNotation)
1921: {
1922: attributeStart = dest.length();
1923:
1924: dest.append(symbols.getExponential());
1925:
1926: addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
1927: attributeStart = dest.length();
1928:
1929: if (exponent < 0)
1930: {
1931: dest.append(symbols.getMinusSign());
1932: exponent = -exponent;
1933:
1934: addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
1935: }
1936:
1937: attributeStart = dest.length();
1938:
1939: String exponentString = String.valueOf(exponent);
1940: int exponentLength = exponentString.length();
1941:
1942: for (int i = 0; i < minExponentDigits - exponentLength; i++)
1943: dest.append(symbols.getZeroDigit());
1944:
1945: for (int i = 0; i < exponentLength; ++i)
1946: dest.append(exponentString.charAt(i));
1947:
1948: addAttribute(Field.EXPONENT, attributeStart, dest.length());
1949: }
1950:
1951:
1952: if (isNegative)
1953: {
1954: dest.append(negativeSuffix);
1955: }
1956: else
1957: {
1958: dest.append(positiveSuffix);
1959: }
1960: }
1961:
1962:
1971: private void handleFractionalPart(StringBuffer dest, String fractPart,
1972: FieldPosition fieldPos, boolean isLong)
1973: {
1974: int dotStart = 0;
1975: int dotEnd = 0;
1976: boolean addDecimal = false;
1977:
1978: if (this.decimalSeparatorAlwaysShown ||
1979: ((!isLong || this.useExponentialNotation) &&
1980: this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
1981: this.minimumFractionDigits > 0)
1982: {
1983: dotStart = dest.length();
1984:
1985: if (this.useCurrencySeparator)
1986: dest.append(symbols.getMonetaryDecimalSeparator());
1987: else
1988: dest.append(symbols.getDecimalSeparator());
1989:
1990: dotEnd = dest.length();
1991: addDecimal = true;
1992: }
1993:
1994:
1995: int fractStart = 0;
1996: int fractEnd = 0;
1997: boolean addFractional = false;
1998:
1999: if ((!isLong || this.useExponentialNotation)
2000: && this.maximumFractionDigits > 0
2001: || this.minimumFractionDigits > 0)
2002: {
2003: fractStart = dest.length();
2004: fractEnd = fractStart;
2005:
2006: int digits = this.minimumFractionDigits;
2007:
2008: if (this.useExponentialNotation)
2009: {
2010: digits = (this.minimumIntegerDigits + this.minimumFractionDigits)
2011: - dest.length();
2012: if (digits < 0) digits = 0;
2013: }
2014:
2015: fractPart = adjustTrailingZeros(fractPart, digits);
2016:
2017:
2018:
2019:
2020: boolean allZeros = true;
2021: char fracts[] = fractPart.toCharArray();
2022: for (int i = 0; i < fracts.length; i++)
2023: {
2024: if (fracts[i] != '0')
2025: allZeros = false;
2026: }
2027:
2028: if (!allZeros || (minimumFractionDigits > 0))
2029: {
2030: appendDigit(fractPart, dest, false);
2031: fractEnd = dest.length();
2032:
2033: addDecimal = true;
2034: addFractional = true;
2035: }
2036: else if (!this.decimalSeparatorAlwaysShown)
2037: {
2038: dest.deleteCharAt(dest.length() - 1);
2039: addDecimal = false;
2040: }
2041: else
2042: {
2043: fractEnd = dest.length();
2044: addFractional = true;
2045: }
2046: }
2047:
2048: if (addDecimal)
2049: addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
2050:
2051: if (addFractional)
2052: addAttribute(Field.FRACTION, fractStart, fractEnd);
2053:
2054: if ((fieldPos.getField() == FRACTION_FIELD ||
2055: fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
2056: {
2057: fieldPos.setBeginIndex(fractStart);
2058: fieldPos.setEndIndex(fractEnd);
2059: }
2060: }
2061:
2062:
2068: private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount)
2069: {
2070: char ch = symbols.getZeroDigit();
2071: char gSeparator = symbols.getGroupingSeparator();
2072:
2073: int i = 0;
2074: int gPos = totalDigitCount;
2075: for (i = 0; i < zeroes; i++, gPos--)
2076: {
2077: if (this.groupingSeparatorInPattern &&
2078: (this.groupingUsed && this.groupingSize != 0) &&
2079: (gPos % groupingSize == 0 && i > 0))
2080: dest.append(gSeparator);
2081:
2082: dest.append(ch);
2083: }
2084:
2085:
2086: if (this.groupingSeparatorInPattern &&
2087: (this.groupingUsed && this.groupingSize != 0) &&
2088: (gPos % groupingSize == 0))
2089: dest.append(gSeparator);
2090: }
2091:
2092:
2098: private void appendDigit(String src, StringBuffer dest,
2099: boolean groupingUsed)
2100: {
2101: int zero = symbols.getZeroDigit() - '0';
2102:
2103: int ch;
2104: char gSeparator = symbols.getGroupingSeparator();
2105:
2106: int len = src.length();
2107: for (int i = 0, gPos = len; i < len; i++, gPos--)
2108: {
2109: ch = src.charAt(i);
2110: if (groupingUsed && this.groupingSize != 0 &&
2111: gPos % groupingSize == 0 && i > 0)
2112: dest.append(gSeparator);
2113:
2114: dest.append((char) (zero + ch));
2115: }
2116: }
2117:
2118:
2124: private long getExponent(BigDecimal number)
2125: {
2126: long exponent = 0;
2127:
2128: if (number.signum() > 0)
2129: {
2130: double _number = number.doubleValue();
2131: exponent = (long) Math.floor (Math.log10(_number));
2132:
2133:
2134: exponent = exponent - (exponent % this.exponentRound);
2135:
2136:
2137:
2138:
2139:
2140:
2141:
2142:
2143: if (minimumIntegerDigits > 0)
2144: exponent -= minimumIntegerDigits - 1;
2145: }
2146:
2147: return exponent;
2148: }
2149:
2150:
2162: private String adjustTrailingZeros(String src, int minimumDigits)
2163: {
2164: int len = src.length();
2165: String result;
2166:
2167:
2168: if (len > minimumDigits)
2169: {
2170: int zeros = 0;
2171: for (int i = len - 1; i > minimumDigits; i--)
2172: {
2173: if (src.charAt(i) == '0')
2174: ++zeros;
2175: else
2176: break;
2177: }
2178: result = src.substring(0, len - zeros);
2179: }
2180: else
2181: {
2182: char zero = symbols.getZeroDigit();
2183: StringBuffer _result = new StringBuffer(src);
2184: for (int i = len; i < minimumDigits; i++)
2185: {
2186: _result.append(zero);
2187: }
2188: result = _result.toString();
2189: }
2190:
2191: return result;
2192: }
2193:
2194:
2201: private void addAttribute(Field field, int begin, int end)
2202: {
2203:
2207:
2208: FieldPosition pos = new FieldPosition(field);
2209: pos.setBeginIndex(begin);
2210: pos.setEndIndex(end);
2211: attributes.add(pos);
2212: }
2213:
2214:
2217: private void setDefaultValues()
2218: {
2219:
2220:
2221:
2222:
2223:
2224: this.negativePrefix = String.valueOf(symbols.getMinusSign());
2225: this.negativeSuffix = "";
2226: this.positivePrefix = "";
2227: this.positiveSuffix = "";
2228:
2229: this.multiplier = 1;
2230: this.negativePatternMultiplier = 1;
2231: this.exponentRound = 1;
2232:
2233: this.hasNegativePrefix = false;
2234:
2235: this.minimumIntegerDigits = 1;
2236: this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
2237: this.minimumFractionDigits = 0;
2238: this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
2239: this.minExponentDigits = 0;
2240:
2241: this.groupingSize = 0;
2242:
2243: this.decimalSeparatorAlwaysShown = false;
2244: this.showDecimalSeparator = false;
2245: this.useExponentialNotation = false;
2246: this.groupingUsed = false;
2247: this.groupingSeparatorInPattern = false;
2248:
2249: this.useCurrencySeparator = false;
2250:
2251: this.hasFractionalPattern = false;
2252: }
2253: }