DecimalFormat.java 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279
  1. /* DecimalFormat.java -- Formats and parses numbers
  2. Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2012 Free Software Foundation, Inc.
  3. This file is part of GNU Classpath.
  4. GNU Classpath is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Classpath is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Classpath; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  15. 02110-1301 USA.
  16. Linking this library statically or dynamically with other modules is
  17. making a combined work based on this library. Thus, the terms and
  18. conditions of the GNU General Public License cover the whole
  19. combination.
  20. As a special exception, the copyright holders of this library give you
  21. permission to link this library with independent modules to produce an
  22. executable, regardless of the license terms of these independent
  23. modules, and to copy and distribute the resulting executable under
  24. terms of your choice, provided that you also meet, for each linked
  25. independent module, the terms and conditions of the license of that
  26. module. An independent module is a module which is not derived from
  27. or based on this library. If you modify this library, you may extend
  28. this exception to your version of the library, but you are not
  29. obligated to do so. If you do not wish to do so, delete this
  30. exception statement from your version. */
  31. /*
  32. * This class contains few bits from ICU4J (http://icu.sourceforge.net/),
  33. * Copyright by IBM and others and distributed under the
  34. * distributed under MIT/X.
  35. */
  36. package java.text;
  37. import gnu.java.lang.CPStringBuilder;
  38. import java.math.BigDecimal;
  39. import java.math.BigInteger;
  40. import java.util.ArrayList;
  41. import java.util.Currency;
  42. import java.util.Locale;
  43. /*
  44. * This note is here for historical reasons and because I had not the courage
  45. * to remove it :)
  46. *
  47. * @author Tom Tromey (tromey@cygnus.com)
  48. * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  49. * @date March 4, 1999
  50. *
  51. * Written using "Java Class Libraries", 2nd edition, plus online
  52. * API docs for JDK 1.2 from http://www.javasoft.com.
  53. * Status: Believed complete and correct to 1.2.
  54. * Note however that the docs are very unclear about how format parsing
  55. * should work. No doubt there are problems here.
  56. */
  57. /**
  58. * This class is a concrete implementation of NumberFormat used to format
  59. * decimal numbers. The class can format numbers given a specific locale.
  60. * Generally, to get an instance of DecimalFormat you should call the factory
  61. * methods in the <code>NumberFormat</code> base class.
  62. *
  63. * @author Mario Torre (neugens@limasoftware.net)
  64. * @author Tom Tromey (tromey@cygnus.com)
  65. * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
  66. */
  67. public class DecimalFormat extends NumberFormat
  68. {
  69. /** serialVersionUID for serializartion. */
  70. private static final long serialVersionUID = 864413376551465018L;
  71. /** Defines the default number of digits allowed while formatting integers. */
  72. private static final int DEFAULT_INTEGER_DIGITS = 309;
  73. /**
  74. * Defines the default number of digits allowed while formatting
  75. * fractions.
  76. */
  77. private static final int DEFAULT_FRACTION_DIGITS = 340;
  78. /**
  79. * Locale-independent pattern symbols.
  80. */
  81. // Happen to be the same as the US symbols.
  82. private static final DecimalFormatSymbols nonLocalizedSymbols
  83. = new DecimalFormatSymbols (Locale.US);
  84. /**
  85. * Defines if parse should return a BigDecimal or not.
  86. */
  87. private boolean parseBigDecimal;
  88. /**
  89. * Defines if we have to use the monetary decimal separator or
  90. * the decimal separator while formatting numbers.
  91. */
  92. private boolean useCurrencySeparator;
  93. /** Defines if the decimal separator is always shown or not. */
  94. private boolean decimalSeparatorAlwaysShown;
  95. /**
  96. * Defines if the decimal separator has to be shown.
  97. *
  98. * This is different then <code>decimalSeparatorAlwaysShown</code>,
  99. * as it defines if the format string contains a decimal separator or no.
  100. */
  101. private boolean showDecimalSeparator;
  102. /**
  103. * This field is used to determine if the grouping
  104. * separator is included in the format string or not.
  105. * This is only needed to match the behaviour of the RI.
  106. */
  107. private boolean groupingSeparatorInPattern;
  108. /** Defines the size of grouping groups when grouping is used. */
  109. private byte groupingSize;
  110. /**
  111. * This is an internal parameter used to keep track of the number
  112. * of digits the form the exponent, when exponential notation is used.
  113. * It is used with <code>exponentRound</code>
  114. */
  115. private byte minExponentDigits;
  116. /** This field is used to set the exponent in the engineering notation. */
  117. private int exponentRound;
  118. /** Multiplier used in percent style formats. */
  119. private int multiplier;
  120. /** Multiplier used in percent style formats. */
  121. private int negativePatternMultiplier;
  122. /** The negative prefix. */
  123. private String negativePrefix;
  124. /** The negative suffix. */
  125. private String negativeSuffix;
  126. /** The positive prefix. */
  127. private String positivePrefix;
  128. /** The positive suffix. */
  129. private String positiveSuffix;
  130. /** Decimal Format Symbols for the given locale. */
  131. private DecimalFormatSymbols symbols;
  132. /** Determine if we have to use exponential notation or not. */
  133. private boolean useExponentialNotation;
  134. /**
  135. * Defines the maximum number of integer digits to show when we use
  136. * the exponential notation.
  137. */
  138. private int maxIntegerDigitsExponent;
  139. /** Defines if the format string has a negative prefix or not. */
  140. private boolean hasNegativePrefix;
  141. /** Defines if the format string has a fractional pattern or not. */
  142. private boolean hasFractionalPattern;
  143. /** Stores a list of attributes for use by formatToCharacterIterator. */
  144. private ArrayList<FieldPosition> attributes = new ArrayList<FieldPosition>();
  145. /**
  146. * Constructs a <code>DecimalFormat</code> which uses the default
  147. * pattern and symbols.
  148. */
  149. public DecimalFormat()
  150. {
  151. this ("#,##0.###");
  152. }
  153. /**
  154. * Constructs a <code>DecimalFormat</code> which uses the given
  155. * pattern and the default symbols for formatting and parsing.
  156. *
  157. * @param pattern the non-localized pattern to use.
  158. * @throws NullPointerException if any argument is null.
  159. * @throws IllegalArgumentException if the pattern is invalid.
  160. */
  161. public DecimalFormat(String pattern)
  162. {
  163. this (pattern, new DecimalFormatSymbols());
  164. }
  165. /**
  166. * Constructs a <code>DecimalFormat</code> using the given pattern
  167. * and formatting symbols. This construction method is used to give
  168. * complete control over the formatting process.
  169. *
  170. * @param pattern the non-localized pattern to use.
  171. * @param symbols the set of symbols used for parsing and formatting.
  172. * @throws NullPointerException if any argument is null.
  173. * @throws IllegalArgumentException if the pattern is invalid.
  174. */
  175. public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
  176. {
  177. this.symbols = (DecimalFormatSymbols) symbols.clone();
  178. applyPatternWithSymbols(pattern, nonLocalizedSymbols);
  179. }
  180. /**
  181. * Apply the given localized patern to the current DecimalFormat object.
  182. *
  183. * @param pattern The localized pattern to apply.
  184. * @throws IllegalArgumentException if the given pattern is invalid.
  185. * @throws NullPointerException if the input pattern is null.
  186. */
  187. public void applyLocalizedPattern (String pattern)
  188. {
  189. applyPatternWithSymbols(pattern, this.symbols);
  190. }
  191. /**
  192. * Apply the given localized pattern to the current DecimalFormat object.
  193. *
  194. * @param pattern The localized pattern to apply.
  195. * @throws IllegalArgumentException if the given pattern is invalid.
  196. * @throws NullPointerException if the input pattern is null.
  197. */
  198. public void applyPattern(String pattern)
  199. {
  200. applyPatternWithSymbols(pattern, nonLocalizedSymbols);
  201. }
  202. public Object clone()
  203. {
  204. DecimalFormat c = (DecimalFormat) super.clone();
  205. c.symbols = (DecimalFormatSymbols) symbols.clone();
  206. return c;
  207. }
  208. /**
  209. * Tests this instance for equality with an arbitrary object. This method
  210. * returns <code>true</code> if:
  211. * <ul>
  212. * <li><code>obj</code> is not <code>null</code>;</li>
  213. * <li><code>obj</code> is an instance of <code>DecimalFormat</code>;</li>
  214. * <li>this instance and <code>obj</code> have the same attributes;</li>
  215. * </ul>
  216. *
  217. * @param obj the object (<code>null</code> permitted).
  218. *
  219. * @return A boolean.
  220. */
  221. public boolean equals(Object obj)
  222. {
  223. if (! (obj instanceof DecimalFormat))
  224. return false;
  225. DecimalFormat dup = (DecimalFormat) obj;
  226. return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown
  227. && groupingUsed == dup.groupingUsed
  228. && groupingSeparatorInPattern == dup.groupingSeparatorInPattern
  229. && groupingSize == dup.groupingSize
  230. && multiplier == dup.multiplier
  231. && useExponentialNotation == dup.useExponentialNotation
  232. && minExponentDigits == dup.minExponentDigits
  233. && minimumIntegerDigits == dup.minimumIntegerDigits
  234. && maximumIntegerDigits == dup.maximumIntegerDigits
  235. && minimumFractionDigits == dup.minimumFractionDigits
  236. && maximumFractionDigits == dup.maximumFractionDigits
  237. && parseBigDecimal == dup.parseBigDecimal
  238. && useCurrencySeparator == dup.useCurrencySeparator
  239. && showDecimalSeparator == dup.showDecimalSeparator
  240. && exponentRound == dup.exponentRound
  241. && negativePatternMultiplier == dup.negativePatternMultiplier
  242. && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent
  243. // XXX: causes equivalent patterns to fail
  244. // && hasNegativePrefix == dup.hasNegativePrefix
  245. && equals(negativePrefix, dup.negativePrefix)
  246. && equals(negativeSuffix, dup.negativeSuffix)
  247. && equals(positivePrefix, dup.positivePrefix)
  248. && equals(positiveSuffix, dup.positiveSuffix)
  249. && symbols.equals(dup.symbols));
  250. }
  251. /**
  252. * Returns a hash code for this object.
  253. *
  254. * @return A hash code.
  255. */
  256. public int hashCode()
  257. {
  258. return toPattern().hashCode();
  259. }
  260. /**
  261. * Produce a formatted {@link String} representation of this object.
  262. * The passed object must be of type number.
  263. *
  264. * @param obj The {@link Number} to format.
  265. * @param sbuf The destination String; text will be appended to this String.
  266. * @param pos If used on input can be used to define an alignment
  267. * field. If used on output defines the offsets of the alignment field.
  268. * @return The String representation of this long.
  269. */
  270. public final StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos)
  271. {
  272. if (obj instanceof BigInteger)
  273. {
  274. BigDecimal decimal = new BigDecimal((BigInteger) obj);
  275. formatInternal(decimal, true, sbuf, pos);
  276. return sbuf;
  277. }
  278. else if (obj instanceof BigDecimal)
  279. {
  280. formatInternal((BigDecimal) obj, true, sbuf, pos);
  281. return sbuf;
  282. }
  283. return super.format(obj, sbuf, pos);
  284. }
  285. /**
  286. * Produce a formatted {@link String} representation of this double.
  287. *
  288. * @param number The double to format.
  289. * @param dest The destination String; text will be appended to this String.
  290. * @param fieldPos If used on input can be used to define an alignment
  291. * field. If used on output defines the offsets of the alignment field.
  292. * @return The String representation of this long.
  293. * @throws NullPointerException if <code>dest</code> or fieldPos are null
  294. */
  295. public StringBuffer format(double number, StringBuffer dest,
  296. FieldPosition fieldPos)
  297. {
  298. // special cases for double: NaN and negative or positive infinity
  299. if (Double.isNaN(number))
  300. {
  301. // 1. NaN
  302. String nan = symbols.getNaN();
  303. dest.append(nan);
  304. // update field position if required
  305. if ((fieldPos.getField() == INTEGER_FIELD ||
  306. fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
  307. {
  308. int index = dest.length();
  309. fieldPos.setBeginIndex(index - nan.length());
  310. fieldPos.setEndIndex(index);
  311. }
  312. }
  313. else if (Double.isInfinite(number))
  314. {
  315. // 2. Infinity
  316. if (number < 0)
  317. dest.append(this.negativePrefix);
  318. else
  319. dest.append(this.positivePrefix);
  320. dest.append(symbols.getInfinity());
  321. if (number < 0)
  322. dest.append(this.negativeSuffix);
  323. else
  324. dest.append(this.positiveSuffix);
  325. if ((fieldPos.getField() == INTEGER_FIELD ||
  326. fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
  327. {
  328. fieldPos.setBeginIndex(dest.length());
  329. fieldPos.setEndIndex(0);
  330. }
  331. }
  332. else
  333. {
  334. // get the number as a BigDecimal
  335. BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
  336. formatInternal(bigDecimal, false, dest, fieldPos);
  337. }
  338. return dest;
  339. }
  340. /**
  341. * Produce a formatted {@link String} representation of this long.
  342. *
  343. * @param number The long to format.
  344. * @param dest The destination String; text will be appended to this String.
  345. * @param fieldPos If used on input can be used to define an alignment
  346. * field. If used on output defines the offsets of the alignment field.
  347. * @return The String representation of this long.
  348. */
  349. public StringBuffer format(long number, StringBuffer dest,
  350. FieldPosition fieldPos)
  351. {
  352. BigDecimal bigDecimal = new BigDecimal(String.valueOf(number));
  353. formatInternal(bigDecimal, true, dest, fieldPos);
  354. return dest;
  355. }
  356. /**
  357. * Return an <code>AttributedCharacterIterator</code> as a result of
  358. * the formatting of the passed {@link Object}.
  359. *
  360. * @return An {@link AttributedCharacterIterator}.
  361. * @throws NullPointerException if value is <code>null</code>.
  362. * @throws IllegalArgumentException if value is not an instance of
  363. * {@link Number}.
  364. */
  365. public AttributedCharacterIterator formatToCharacterIterator(Object value)
  366. {
  367. /*
  368. * This method implementation derives directly from the
  369. * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
  370. */
  371. if (value == null)
  372. throw new NullPointerException("Passed Object is null");
  373. if (!(value instanceof Number)) throw new
  374. IllegalArgumentException("Cannot format given Object as a Number");
  375. StringBuffer text = new StringBuffer();
  376. attributes.clear();
  377. super.format(value, text, new FieldPosition(0));
  378. AttributedString as = new AttributedString(text.toString());
  379. // add NumberFormat field attributes to the AttributedString
  380. for (int i = 0; i < attributes.size(); i++)
  381. {
  382. FieldPosition pos = attributes.get(i);
  383. Format.Field attribute = pos.getFieldAttribute();
  384. as.addAttribute(attribute, attribute, pos.getBeginIndex(),
  385. pos.getEndIndex());
  386. }
  387. // return the CharacterIterator from AttributedString
  388. return as.getIterator();
  389. }
  390. /**
  391. * Returns the currency corresponding to the currency symbol stored
  392. * in the instance of <code>DecimalFormatSymbols</code> used by this
  393. * <code>DecimalFormat</code>.
  394. *
  395. * @return A new instance of <code>Currency</code> if
  396. * the currency code matches a known one, null otherwise.
  397. */
  398. public Currency getCurrency()
  399. {
  400. return symbols.getCurrency();
  401. }
  402. /**
  403. * Returns a copy of the symbols used by this instance.
  404. *
  405. * @return A copy of the symbols.
  406. */
  407. public DecimalFormatSymbols getDecimalFormatSymbols()
  408. {
  409. return (DecimalFormatSymbols) symbols.clone();
  410. }
  411. /**
  412. * Gets the interval used between a grouping separator and the next.
  413. * For example, a grouping size of 3 means that the number 1234 is
  414. * formatted as 1,234.
  415. *
  416. * The actual character used as grouping separator depends on the
  417. * locale and is defined by {@link DecimalFormatSymbols#getDecimalSeparator()}
  418. *
  419. * @return The interval used between a grouping separator and the next.
  420. */
  421. public int getGroupingSize()
  422. {
  423. return groupingSize;
  424. }
  425. /**
  426. * Gets the multiplier used in percent and similar formats.
  427. *
  428. * @return The multiplier used in percent and similar formats.
  429. */
  430. public int getMultiplier()
  431. {
  432. return multiplier;
  433. }
  434. /**
  435. * Gets the negative prefix.
  436. *
  437. * @return The negative prefix.
  438. */
  439. public String getNegativePrefix()
  440. {
  441. return negativePrefix;
  442. }
  443. /**
  444. * Gets the negative suffix.
  445. *
  446. * @return The negative suffix.
  447. */
  448. public String getNegativeSuffix()
  449. {
  450. return negativeSuffix;
  451. }
  452. /**
  453. * Gets the positive prefix.
  454. *
  455. * @return The positive prefix.
  456. */
  457. public String getPositivePrefix()
  458. {
  459. return positivePrefix;
  460. }
  461. /**
  462. * Gets the positive suffix.
  463. *
  464. * @return The positive suffix.
  465. */
  466. public String getPositiveSuffix()
  467. {
  468. return positiveSuffix;
  469. }
  470. public boolean isDecimalSeparatorAlwaysShown()
  471. {
  472. return decimalSeparatorAlwaysShown;
  473. }
  474. /**
  475. * Define if <code>parse(java.lang.String, java.text.ParsePosition)</code>
  476. * should return a {@link BigDecimal} or not.
  477. *
  478. * @param newValue
  479. */
  480. public void setParseBigDecimal(boolean newValue)
  481. {
  482. this.parseBigDecimal = newValue;
  483. }
  484. /**
  485. * Returns <code>true</code> if
  486. * <code>parse(java.lang.String, java.text.ParsePosition)</code> returns
  487. * a <code>BigDecimal</code>, <code>false</code> otherwise.
  488. * The default return value for this method is <code>false</code>.
  489. *
  490. * @return <code>true</code> if the parse method returns a {@link BigDecimal},
  491. * <code>false</code> otherwise.
  492. * @since 1.5
  493. * @see #setParseBigDecimal(boolean)
  494. */
  495. public boolean isParseBigDecimal()
  496. {
  497. return this.parseBigDecimal;
  498. }
  499. /**
  500. * This method parses the specified string into a <code>Number</code>.
  501. *
  502. * The parsing starts at <code>pos</code>, which is updated as the parser
  503. * consume characters in the passed string.
  504. * On error, the <code>Position</code> object index is not updated, while
  505. * error position is set appropriately, an <code>null</code> is returned.
  506. *
  507. * @param str The string to parse.
  508. * @param pos The desired <code>ParsePosition</code>.
  509. *
  510. * @return The parsed <code>Number</code>
  511. */
  512. public Number parse(String str, ParsePosition pos)
  513. {
  514. // a special values before anything else
  515. // NaN
  516. if (str.contains(this.symbols.getNaN()))
  517. return Double.valueOf(Double.NaN);
  518. // this will be our final number
  519. CPStringBuilder number = new CPStringBuilder();
  520. // special character
  521. char minus = symbols.getMinusSign();
  522. // starting parsing position
  523. int start = pos.getIndex();
  524. // validate the string, it have to be in the
  525. // same form as the format string or parsing will fail
  526. String _negativePrefix = (this.negativePrefix.compareTo("") == 0
  527. ? minus + positivePrefix
  528. : this.negativePrefix);
  529. // we check both prefixes, because one might be empty.
  530. // We want to pick the longest prefix that matches.
  531. int positiveLen = positivePrefix.length();
  532. int negativeLen = _negativePrefix.length();
  533. boolean isNegative = str.startsWith(_negativePrefix);
  534. boolean isPositive = str.startsWith(positivePrefix);
  535. if (isPositive && isNegative)
  536. {
  537. // By checking this way, we preserve ambiguity in the case
  538. // where the negative format differs only in suffix.
  539. if (negativeLen > positiveLen)
  540. {
  541. start += _negativePrefix.length();
  542. isNegative = true;
  543. }
  544. else
  545. {
  546. start += positivePrefix.length();
  547. isPositive = true;
  548. if (negativeLen < positiveLen)
  549. isNegative = false;
  550. }
  551. }
  552. else if (isNegative)
  553. {
  554. start += _negativePrefix.length();
  555. isPositive = false;
  556. }
  557. else if (isPositive)
  558. {
  559. start += positivePrefix.length();
  560. isNegative = false;
  561. }
  562. else
  563. {
  564. pos.setErrorIndex(start);
  565. return null;
  566. }
  567. // other special characters used by the parser
  568. char decimalSeparator = symbols.getDecimalSeparator();
  569. char zero = symbols.getZeroDigit();
  570. char exponent = symbols.getExponential();
  571. // stop parsing position in the string
  572. int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2;
  573. if (useExponentialNotation)
  574. stop += minExponentDigits + 1;
  575. boolean inExponent = false;
  576. // correct the size of the end parsing flag
  577. int len = str.length();
  578. if (len < stop) stop = len;
  579. char groupingSeparator = symbols.getGroupingSeparator();
  580. int i = start;
  581. while (i < stop)
  582. {
  583. char ch = str.charAt(i);
  584. i++;
  585. if (ch >= zero && ch <= (zero + 9))
  586. {
  587. number.append(ch);
  588. }
  589. else if (this.parseIntegerOnly)
  590. {
  591. i--;
  592. break;
  593. }
  594. else if (ch == decimalSeparator)
  595. {
  596. number.append('.');
  597. }
  598. else if (ch == exponent)
  599. {
  600. number.append(ch);
  601. inExponent = !inExponent;
  602. }
  603. else if ((ch == '+' || ch == '-' || ch == minus))
  604. {
  605. if (inExponent)
  606. number.append(ch);
  607. else
  608. {
  609. i--;
  610. break;
  611. }
  612. }
  613. else
  614. {
  615. if (!groupingUsed || ch != groupingSeparator)
  616. {
  617. i--;
  618. break;
  619. }
  620. }
  621. }
  622. // 2nd special case: infinity
  623. // XXX: need to be tested
  624. if (str.contains(symbols.getInfinity()))
  625. {
  626. int inf = str.indexOf(symbols.getInfinity());
  627. pos.setIndex(inf);
  628. // FIXME: ouch, this is really ugly and lazy code...
  629. if (this.parseBigDecimal)
  630. {
  631. if (isNegative)
  632. return BigDecimal.valueOf(Double.NEGATIVE_INFINITY);
  633. return BigDecimal.valueOf(Double.POSITIVE_INFINITY);
  634. }
  635. if (isNegative)
  636. return Double.valueOf(Double.NEGATIVE_INFINITY);
  637. return Double.valueOf(Double.POSITIVE_INFINITY);
  638. }
  639. // no number...
  640. if (i == start || number.length() == 0)
  641. {
  642. pos.setErrorIndex(i);
  643. return null;
  644. }
  645. // now we have to check the suffix, done here after number parsing
  646. // or the index will not be updated correctly...
  647. boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix);
  648. boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix);
  649. boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix);
  650. positiveLen = positiveSuffix.length();
  651. negativeLen = negativeSuffix.length();
  652. if (isNegative && !hasNegativeSuffix)
  653. {
  654. pos.setErrorIndex(i);
  655. return null;
  656. }
  657. else if (hasNegativeSuffix &&
  658. !positiveEqualsNegative &&
  659. (negativeLen > positiveLen))
  660. {
  661. isNegative = true;
  662. }
  663. else if (!hasPositiveSuffix)
  664. {
  665. pos.setErrorIndex(i);
  666. return null;
  667. }
  668. if (isNegative) number.insert(0, '-');
  669. pos.setIndex(i);
  670. // now we handle the return type
  671. BigDecimal bigDecimal = new BigDecimal(number.toString());
  672. if (this.parseBigDecimal)
  673. return bigDecimal;
  674. // want integer?
  675. if (this.parseIntegerOnly)
  676. return Long.valueOf(bigDecimal.longValue());
  677. // 3th special case -0.0
  678. if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0))
  679. return Double.valueOf(-0.0);
  680. try
  681. {
  682. BigDecimal integer
  683. = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY);
  684. return Long.valueOf(integer.longValue());
  685. }
  686. catch (ArithmeticException e)
  687. {
  688. return Double.valueOf(bigDecimal.doubleValue());
  689. }
  690. }
  691. /**
  692. * Sets the <code>Currency</code> on the
  693. * <code>DecimalFormatSymbols</code> used, which also sets the
  694. * currency symbols on those symbols.
  695. *
  696. * @param currency The new <code>Currency</code> on the
  697. * <code>DecimalFormatSymbols</code>.
  698. */
  699. public void setCurrency(Currency currency)
  700. {
  701. Currency current = symbols.getCurrency();
  702. if (current != currency)
  703. {
  704. String oldSymbol = symbols.getCurrencySymbol();
  705. int len = oldSymbol.length();
  706. symbols.setCurrency(currency);
  707. String newSymbol = symbols.getCurrencySymbol();
  708. int posPre = positivePrefix.indexOf(oldSymbol);
  709. if (posPre != -1)
  710. positivePrefix = positivePrefix.substring(0, posPre) +
  711. newSymbol + positivePrefix.substring(posPre+len);
  712. int negPre = negativePrefix.indexOf(oldSymbol);
  713. if (negPre != -1)
  714. negativePrefix = negativePrefix.substring(0, negPre) +
  715. newSymbol + negativePrefix.substring(negPre+len);
  716. int posSuf = positiveSuffix.indexOf(oldSymbol);
  717. if (posSuf != -1)
  718. positiveSuffix = positiveSuffix.substring(0, posSuf) +
  719. newSymbol + positiveSuffix.substring(posSuf+len);
  720. int negSuf = negativeSuffix.indexOf(oldSymbol);
  721. if (negSuf != -1)
  722. negativeSuffix = negativeSuffix.substring(0, negSuf) +
  723. newSymbol + negativeSuffix.substring(negSuf+len);
  724. }
  725. }
  726. /**
  727. * Sets the symbols used by this instance. This method makes a copy of
  728. * the supplied symbols.
  729. *
  730. * @param newSymbols the symbols (<code>null</code> not permitted).
  731. */
  732. public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
  733. {
  734. symbols = (DecimalFormatSymbols) newSymbols.clone();
  735. }
  736. /**
  737. * Define if the decimal separator should be always visible or only
  738. * visible when needed. This method as effect only on integer values.
  739. * Pass <code>true</code> if you want the decimal separator to be
  740. * always shown, <code>false</code> otherwise.
  741. *
  742. * @param newValue true</code> if you want the decimal separator to be
  743. * always shown, <code>false</code> otherwise.
  744. */
  745. public void setDecimalSeparatorAlwaysShown(boolean newValue)
  746. {
  747. decimalSeparatorAlwaysShown = newValue;
  748. }
  749. /**
  750. * Sets the number of digits used to group portions of the integer part of
  751. * the number. For example, the number <code>123456</code>, with a grouping
  752. * size of 3, is rendered <code>123,456</code>.
  753. *
  754. * @param groupSize The number of digits used while grouping portions
  755. * of the integer part of a number.
  756. */
  757. public void setGroupingSize(int groupSize)
  758. {
  759. groupingSize = (byte) groupSize;
  760. }
  761. /**
  762. * Sets the maximum number of digits allowed in the integer
  763. * portion of a number to the specified value.
  764. * The new value will be the choosen as the minimum between
  765. * <code>newvalue</code> and 309. Any value below zero will be
  766. * replaced by zero.
  767. *
  768. * @param newValue The new maximum integer digits value.
  769. */
  770. public void setMaximumIntegerDigits(int newValue)
  771. {
  772. newValue = (newValue > 0) ? newValue : 0;
  773. super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
  774. }
  775. /**
  776. * Sets the minimum number of digits allowed in the integer
  777. * portion of a number to the specified value.
  778. * The new value will be the choosen as the minimum between
  779. * <code>newvalue</code> and 309. Any value below zero will be
  780. * replaced by zero.
  781. *
  782. * @param newValue The new minimum integer digits value.
  783. */
  784. public void setMinimumIntegerDigits(int newValue)
  785. {
  786. newValue = (newValue > 0) ? newValue : 0;
  787. super.setMinimumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS));
  788. }
  789. /**
  790. * Sets the maximum number of digits allowed in the fraction
  791. * portion of a number to the specified value.
  792. * The new value will be the choosen as the minimum between
  793. * <code>newvalue</code> and 309. Any value below zero will be
  794. * replaced by zero.
  795. *
  796. * @param newValue The new maximum fraction digits value.
  797. */
  798. public void setMaximumFractionDigits(int newValue)
  799. {
  800. newValue = (newValue > 0) ? newValue : 0;
  801. super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
  802. }
  803. /**
  804. * Sets the minimum number of digits allowed in the fraction
  805. * portion of a number to the specified value.
  806. * The new value will be the choosen as the minimum between
  807. * <code>newvalue</code> and 309. Any value below zero will be
  808. * replaced by zero.
  809. *
  810. * @param newValue The new minimum fraction digits value.
  811. */
  812. public void setMinimumFractionDigits(int newValue)
  813. {
  814. newValue = (newValue > 0) ? newValue : 0;
  815. super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS));
  816. }
  817. /**
  818. * Sets the multiplier for use in percent and similar formats.
  819. * For example, for percent set the multiplier to 100, for permille, set the
  820. * miltiplier to 1000.
  821. *
  822. * @param newValue the new value for multiplier.
  823. */
  824. public void setMultiplier(int newValue)
  825. {
  826. multiplier = newValue;
  827. }
  828. /**
  829. * Sets the negative prefix.
  830. *
  831. * @param newValue The new negative prefix.
  832. */
  833. public void setNegativePrefix(String newValue)
  834. {
  835. negativePrefix = newValue;
  836. }
  837. /**
  838. * Sets the negative suffix.
  839. *
  840. * @param newValue The new negative suffix.
  841. */
  842. public void setNegativeSuffix(String newValue)
  843. {
  844. negativeSuffix = newValue;
  845. }
  846. /**
  847. * Sets the positive prefix.
  848. *
  849. * @param newValue The new positive prefix.
  850. */
  851. public void setPositivePrefix(String newValue)
  852. {
  853. positivePrefix = newValue;
  854. }
  855. /**
  856. * Sets the new positive suffix.
  857. *
  858. * @param newValue The new positive suffix.
  859. */
  860. public void setPositiveSuffix(String newValue)
  861. {
  862. positiveSuffix = newValue;
  863. }
  864. /**
  865. * This method returns a string with the formatting pattern being used
  866. * by this object. The string is localized.
  867. *
  868. * @return A localized <code>String</code> with the formatting pattern.
  869. * @see #toPattern()
  870. */
  871. public String toLocalizedPattern()
  872. {
  873. return computePattern(this.symbols);
  874. }
  875. /**
  876. * This method returns a string with the formatting pattern being used
  877. * by this object. The string is not localized.
  878. *
  879. * @return A <code>String</code> with the formatting pattern.
  880. * @see #toLocalizedPattern()
  881. */
  882. public String toPattern()
  883. {
  884. return computePattern(nonLocalizedSymbols);
  885. }
  886. /* ***** private methods ***** */
  887. /**
  888. * This is an shortcut helper method used to test if two given strings are
  889. * equals.
  890. *
  891. * @param s1 The first string to test for equality.
  892. * @param s2 The second string to test for equality.
  893. * @return <code>true</code> if the strings are both <code>null</code> or
  894. * equals.
  895. */
  896. private boolean equals(String s1, String s2)
  897. {
  898. if (s1 == null || s2 == null)
  899. return s1 == s2;
  900. return s1.equals(s2);
  901. }
  902. /* ****** PATTERN ****** */
  903. /**
  904. * This helper function creates a string consisting of all the
  905. * characters which can appear in a pattern and must be quoted.
  906. */
  907. private String patternChars (DecimalFormatSymbols syms)
  908. {
  909. CPStringBuilder buf = new CPStringBuilder ();
  910. buf.append(syms.getDecimalSeparator());
  911. buf.append(syms.getDigit());
  912. buf.append(syms.getExponential());
  913. buf.append(syms.getGroupingSeparator());
  914. buf.append(syms.getMinusSign());
  915. buf.append(syms.getPatternSeparator());
  916. buf.append(syms.getPercent());
  917. buf.append(syms.getPerMill());
  918. buf.append(syms.getZeroDigit());
  919. buf.append('\'');
  920. buf.append('\u00a4');
  921. return buf.toString();
  922. }
  923. /**
  924. * Quote special characters as defined by <code>patChars</code> in the
  925. * input string.
  926. *
  927. * @param text
  928. * @param patChars
  929. * @return A StringBuffer with special characters quoted.
  930. */
  931. private CPStringBuilder quoteFix(String text, String patChars)
  932. {
  933. CPStringBuilder buf = new CPStringBuilder();
  934. int len = text.length();
  935. char ch;
  936. for (int index = 0; index < len; ++index)
  937. {
  938. ch = text.charAt(index);
  939. if (patChars.indexOf(ch) != -1)
  940. {
  941. buf.append('\'');
  942. buf.append(ch);
  943. if (ch != '\'') buf.append('\'');
  944. }
  945. else
  946. {
  947. buf.append(ch);
  948. }
  949. }
  950. return buf;
  951. }
  952. /**
  953. * Returns the format pattern, localized to follow the given
  954. * symbols.
  955. */
  956. private String computePattern(DecimalFormatSymbols symbols)
  957. {
  958. StringBuilder mainPattern = new StringBuilder();
  959. // We have to at least emit a zero for the minimum number of
  960. // digits. Past that we need hash marks up to the grouping
  961. // separator (and one beyond).
  962. int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize;
  963. int totalDigits = Math.max(minimumIntegerDigits, _groupingSize);
  964. // if it is not in exponential notiation,
  965. // we always have a # prebended
  966. if (!useExponentialNotation) mainPattern.append(symbols.getDigit());
  967. for (int i = 1; i < totalDigits - minimumIntegerDigits; i++)
  968. mainPattern.append(symbols.getDigit());
  969. for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++)
  970. mainPattern.append(symbols.getZeroDigit());
  971. if (groupingUsed)
  972. {
  973. mainPattern.insert(mainPattern.length() - groupingSize,
  974. symbols.getGroupingSeparator());
  975. }
  976. // See if we need decimal info.
  977. if (minimumFractionDigits > 0 || maximumFractionDigits > 0 ||
  978. decimalSeparatorAlwaysShown)
  979. {
  980. mainPattern.append(symbols.getDecimalSeparator());
  981. }
  982. for (int i = 0; i < minimumFractionDigits; ++i)
  983. mainPattern.append(symbols.getZeroDigit());
  984. for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
  985. mainPattern.append(symbols.getDigit());
  986. if (useExponentialNotation)
  987. {
  988. mainPattern.append(symbols.getExponential());
  989. for (int i = 0; i < minExponentDigits; ++i)
  990. mainPattern.append(symbols.getZeroDigit());
  991. if (minExponentDigits == 0)
  992. mainPattern.append(symbols.getDigit());
  993. }
  994. // save the pattern
  995. String pattern = mainPattern.toString();
  996. // so far we have the pattern itself, now we need to add
  997. // the positive and the optional negative prefixes and suffixes
  998. String patternChars = patternChars(symbols);
  999. mainPattern.insert(0, quoteFix(positivePrefix, patternChars));
  1000. mainPattern.append(quoteFix(positiveSuffix, patternChars));
  1001. if (hasNegativePrefix)
  1002. {
  1003. mainPattern.append(symbols.getPatternSeparator());
  1004. mainPattern.append(quoteFix(negativePrefix, patternChars));
  1005. mainPattern.append(pattern);
  1006. mainPattern.append(quoteFix(negativeSuffix, patternChars));
  1007. }
  1008. // finally, return the pattern string
  1009. return mainPattern.toString();
  1010. }
  1011. /* ****** FORMAT PARSING ****** */
  1012. /**
  1013. * Scan the input string and define a pattern suitable for use
  1014. * with this decimal format.
  1015. *
  1016. * @param pattern
  1017. * @param symbols
  1018. */
  1019. private void applyPatternWithSymbols(String pattern,
  1020. DecimalFormatSymbols symbols)
  1021. {
  1022. // The pattern string is described by a BNF diagram.
  1023. // we could use a recursive parser to read and prepare
  1024. // the string, but this would be too slow and resource
  1025. // intensive, while this code is quite critical as it is
  1026. // called always when the class is instantiated and every
  1027. // time a new pattern is given.
  1028. // Our strategy is to divide the string into section as given by
  1029. // the BNF diagram, iterating through the string and setting up
  1030. // the parameters we need for formatting (which is basicly what
  1031. // a descendent recursive parser would do - but without recursion).
  1032. // I'm sure that there are smarter methods to do this.
  1033. // Restore default values. Most of these will be overwritten
  1034. // but we want to be sure that nothing is left out.
  1035. setDefaultValues();
  1036. int len = pattern.length();
  1037. if (len == 0)
  1038. {
  1039. // this is another special case...
  1040. this.minimumIntegerDigits = 1;
  1041. this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
  1042. this.minimumFractionDigits = 0;
  1043. this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
  1044. // FIXME: ...and these values may not be valid in all locales
  1045. this.minExponentDigits = 0;
  1046. this.showDecimalSeparator = true;
  1047. this.groupingUsed = true;
  1048. this.groupingSize = 3;
  1049. return;
  1050. }
  1051. int start = scanFix(pattern, symbols, 0, true);
  1052. if (start < len) start = scanNumberInteger(pattern, symbols, start);
  1053. if (start < len)
  1054. {
  1055. start = scanFractionalPortion(pattern, symbols, start);
  1056. }
  1057. else
  1058. {
  1059. // special case, pattern that ends here does not have a fractional
  1060. // portion
  1061. this.minimumFractionDigits = 0;
  1062. this.maximumFractionDigits = 0;
  1063. //this.decimalSeparatorAlwaysShown = false;
  1064. //this.showDecimalSeparator = false;
  1065. }
  1066. // XXX: this fixes a compatibility test with the RI.
  1067. // If new uses cases fail, try removing this line first.
  1068. //if (!this.hasIntegerPattern && !this.hasFractionalPattern)
  1069. // throw new IllegalArgumentException("No valid pattern found!");
  1070. if (start < len) start = scanExponent(pattern, symbols, start);
  1071. if (start < len) start = scanFix(pattern, symbols, start, false);
  1072. if (start < len) scanNegativePattern(pattern, symbols, start);
  1073. if (useExponentialNotation &&
  1074. (maxIntegerDigitsExponent > minimumIntegerDigits) &&
  1075. (maxIntegerDigitsExponent > 1))
  1076. {
  1077. minimumIntegerDigits = 1;
  1078. exponentRound = maxIntegerDigitsExponent;
  1079. }
  1080. if (useExponentialNotation)
  1081. maximumIntegerDigits = maxIntegerDigitsExponent;
  1082. if (!this.hasFractionalPattern && this.showDecimalSeparator == true)
  1083. {
  1084. this.decimalSeparatorAlwaysShown = true;
  1085. }
  1086. }
  1087. /**
  1088. * Scans for the prefix or suffix portion of the pattern string.
  1089. * This method handles the positive subpattern of the pattern string.
  1090. *
  1091. * @param pattern The pattern string to parse.
  1092. * @return The position in the pattern string where parsing ended.
  1093. */
  1094. private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols,
  1095. int start, boolean prefix)
  1096. {
  1097. CPStringBuilder buffer = new CPStringBuilder();
  1098. // the number portion is always delimited by one of those
  1099. // characters
  1100. char decimalSeparator = sourceSymbols.getDecimalSeparator();
  1101. char patternSeparator = sourceSymbols.getPatternSeparator();
  1102. char groupingSeparator = sourceSymbols.getGroupingSeparator();
  1103. char digit = sourceSymbols.getDigit();
  1104. char zero = sourceSymbols.getZeroDigit();
  1105. char minus = sourceSymbols.getMinusSign();
  1106. // other special characters, cached here to avoid method calls later
  1107. char percent = sourceSymbols.getPercent();
  1108. char permille = sourceSymbols.getPerMill();
  1109. String currencySymbol = this.symbols.getCurrencySymbol();
  1110. boolean quote = false;
  1111. char ch = pattern.charAt(start);
  1112. if (ch == patternSeparator)
  1113. {
  1114. // negative subpattern
  1115. this.hasNegativePrefix = true;
  1116. ++start;
  1117. return start;
  1118. }
  1119. int len = pattern.length();
  1120. int i;
  1121. for (i = start; i < len; i++)
  1122. {
  1123. ch = pattern.charAt(i);
  1124. // we are entering into the negative subpattern
  1125. if (!quote && ch == patternSeparator)
  1126. {
  1127. if (this.hasNegativePrefix)
  1128. {
  1129. throw new IllegalArgumentException("Invalid pattern found: "
  1130. + start);
  1131. }
  1132. this.hasNegativePrefix = true;
  1133. ++i;
  1134. break;
  1135. }
  1136. // this means we are inside the number portion
  1137. if (!quote &&
  1138. (ch == minus || ch == digit || ch == zero ||
  1139. ch == groupingSeparator))
  1140. break;
  1141. if (!quote && ch == decimalSeparator)
  1142. {
  1143. this.showDecimalSeparator = true;
  1144. break;
  1145. }
  1146. else if (quote && ch != '\'')
  1147. {
  1148. buffer.append(ch);
  1149. continue;
  1150. }
  1151. if (ch == '\u00A4')
  1152. {
  1153. // CURRENCY
  1154. currencySymbol = this.symbols.getCurrencySymbol();
  1155. // if \u00A4 is doubled, we use the international currency symbol
  1156. if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
  1157. {
  1158. currencySymbol = this.symbols.getInternationalCurrencySymbol();
  1159. i++;
  1160. }
  1161. this.useCurrencySeparator = true;
  1162. buffer.append(currencySymbol);
  1163. }
  1164. else if (ch == percent)
  1165. {
  1166. // PERCENT
  1167. this.multiplier = 100;
  1168. buffer.append(this.symbols.getPercent());
  1169. }
  1170. else if (ch == permille)
  1171. {
  1172. // PERMILLE
  1173. this.multiplier = 1000;
  1174. buffer.append(this.symbols.getPerMill());
  1175. }
  1176. else if (ch == '\'')
  1177. {
  1178. // QUOTE
  1179. if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
  1180. {
  1181. // we need to add ' to the buffer
  1182. buffer.append(ch);
  1183. i++;
  1184. }
  1185. else
  1186. {
  1187. quote = !quote;
  1188. continue;
  1189. }
  1190. }
  1191. else
  1192. {
  1193. buffer.append(ch);
  1194. }
  1195. }
  1196. if (prefix)
  1197. {
  1198. this.positivePrefix = buffer.toString();
  1199. this.negativePrefix = minus + "" + positivePrefix;
  1200. }
  1201. else
  1202. {
  1203. this.positiveSuffix = buffer.toString();
  1204. }
  1205. return i;
  1206. }
  1207. /**
  1208. * Scan the given string for number patterns, starting
  1209. * from <code>start</code>.
  1210. * This method searches the integer part of the pattern only.
  1211. *
  1212. * @param pattern The pattern string to parse.
  1213. * @param start The starting parse position in the string.
  1214. * @return The position in the pattern string where parsing ended,
  1215. * counted from the beginning of the string (that is, 0).
  1216. */
  1217. private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols,
  1218. int start)
  1219. {
  1220. char digit = symbols.getDigit();
  1221. char zero = symbols.getZeroDigit();
  1222. char groupingSeparator = symbols.getGroupingSeparator();
  1223. char decimalSeparator = symbols.getDecimalSeparator();
  1224. char exponent = symbols.getExponential();
  1225. char patternSeparator = symbols.getPatternSeparator();
  1226. // count the number of zeroes in the pattern
  1227. // this number defines the minum digits in the integer portion
  1228. int zeros = 0;
  1229. // count the number of digits used in grouping
  1230. int _groupingSize = 0;
  1231. this.maxIntegerDigitsExponent = 0;
  1232. boolean intPartTouched = false;
  1233. char ch;
  1234. int len = pattern.length();
  1235. int i;
  1236. for (i = start; i < len; i++)
  1237. {
  1238. ch = pattern.charAt(i);
  1239. // break on decimal separator or exponent or pattern separator
  1240. if (ch == decimalSeparator || ch == exponent)
  1241. break;
  1242. if (this.hasNegativePrefix && ch == patternSeparator)
  1243. throw new IllegalArgumentException("Invalid pattern found: "
  1244. + start);
  1245. if (ch == digit)
  1246. {
  1247. // in our implementation we could relax this strict
  1248. // requirement, but this is used to keep compatibility with
  1249. // the RI
  1250. if (zeros > 0) throw new
  1251. IllegalArgumentException("digit mark following zero in " +
  1252. "positive subpattern, not allowed. Position: " + i);
  1253. _groupingSize++;
  1254. intPartTouched = true;
  1255. this.maxIntegerDigitsExponent++;
  1256. }
  1257. else if (ch == zero)
  1258. {
  1259. zeros++;
  1260. _groupingSize++;
  1261. this.maxIntegerDigitsExponent++;
  1262. }
  1263. else if (ch == groupingSeparator)
  1264. {
  1265. this.groupingSeparatorInPattern = true;
  1266. this.groupingUsed = true;
  1267. _groupingSize = 0;
  1268. }
  1269. else
  1270. {
  1271. // any other character not listed above
  1272. // means we are in the suffix portion
  1273. break;
  1274. }
  1275. }
  1276. if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize;
  1277. this.minimumIntegerDigits = zeros;
  1278. // XXX: compatibility code with the RI: the number of minimum integer
  1279. // digits is at least one when maximumIntegerDigits is more than zero
  1280. if (intPartTouched && this.maximumIntegerDigits > 0 &&
  1281. this.minimumIntegerDigits == 0)
  1282. this.minimumIntegerDigits = 1;
  1283. return i;
  1284. }
  1285. /**
  1286. * Scan the given string for number patterns, starting
  1287. * from <code>start</code>.
  1288. * This method searches the fractional part of the pattern only.
  1289. *
  1290. * @param pattern The pattern string to parse.
  1291. * @param start The starting parse position in the string.
  1292. * @return The position in the pattern string where parsing ended,
  1293. * counted from the beginning of the string (that is, 0).
  1294. */
  1295. private int scanFractionalPortion(String pattern,
  1296. DecimalFormatSymbols symbols,
  1297. int start)
  1298. {
  1299. char digit = symbols.getDigit();
  1300. char zero = symbols.getZeroDigit();
  1301. char groupingSeparator = symbols.getGroupingSeparator();
  1302. char decimalSeparator = symbols.getDecimalSeparator();
  1303. char exponent = symbols.getExponential();
  1304. char patternSeparator = symbols.getPatternSeparator();
  1305. // first character needs to be '.' otherwise we are not parsing the
  1306. // fractional portion
  1307. char ch = pattern.charAt(start);
  1308. if (ch != decimalSeparator)
  1309. {
  1310. this.minimumFractionDigits = 0;
  1311. this.maximumFractionDigits = 0;
  1312. return start;
  1313. }
  1314. ++start;
  1315. this.hasFractionalPattern = true;
  1316. this.minimumFractionDigits = 0;
  1317. int digits = 0;
  1318. int len = pattern.length();
  1319. int i;
  1320. for (i = start; i < len; i++)
  1321. {
  1322. ch = pattern.charAt(i);
  1323. // we hit the exponential or negative subpattern
  1324. if (ch == exponent || ch == patternSeparator)
  1325. break;
  1326. // pattern error
  1327. if (ch == groupingSeparator || ch == decimalSeparator) throw new
  1328. IllegalArgumentException("unexpected character '" + ch + "' " +
  1329. "in fractional subpattern. Position: " + i);
  1330. if (ch == digit)
  1331. {
  1332. digits++;
  1333. }
  1334. else if (ch == zero)
  1335. {
  1336. if (digits > 0) throw new
  1337. IllegalArgumentException("digit mark following zero in " +
  1338. "positive subpattern, not allowed. Position: " + i);
  1339. this.minimumFractionDigits++;
  1340. }
  1341. else
  1342. {
  1343. // we are in the suffix section of pattern
  1344. break;
  1345. }
  1346. }
  1347. if (i == start) this.hasFractionalPattern = false;
  1348. this.maximumFractionDigits = this.minimumFractionDigits + digits;
  1349. this.showDecimalSeparator = true;
  1350. return i;
  1351. }
  1352. /**
  1353. * Scan the given string for number patterns, starting
  1354. * from <code>start</code>.
  1355. * This method searches the expoential part of the pattern only.
  1356. *
  1357. * @param pattern The pattern string to parse.
  1358. * @param start The starting parse position in the string.
  1359. * @return The position in the pattern string where parsing ended,
  1360. * counted from the beginning of the string (that is, 0).
  1361. */
  1362. private int scanExponent(String pattern, DecimalFormatSymbols symbols,
  1363. int start)
  1364. {
  1365. char digit = symbols.getDigit();
  1366. char zero = symbols.getZeroDigit();
  1367. char groupingSeparator = symbols.getGroupingSeparator();
  1368. char decimalSeparator = symbols.getDecimalSeparator();
  1369. char exponent = symbols.getExponential();
  1370. char ch = pattern.charAt(start);
  1371. if (ch == decimalSeparator)
  1372. {
  1373. // ignore dots
  1374. ++start;
  1375. }
  1376. if (ch != exponent)
  1377. {
  1378. this.useExponentialNotation = false;
  1379. return start;
  1380. }
  1381. ++start;
  1382. this.minExponentDigits = 0;
  1383. int len = pattern.length();
  1384. int i;
  1385. for (i = start; i < len; i++)
  1386. {
  1387. ch = pattern.charAt(i);
  1388. if (ch == groupingSeparator || ch == decimalSeparator ||
  1389. ch == digit || ch == exponent) throw new
  1390. IllegalArgumentException("unexpected character '" + ch + "' " +
  1391. "in exponential subpattern. Position: " + i);
  1392. if (ch == zero)
  1393. {
  1394. this.minExponentDigits++;
  1395. }
  1396. else
  1397. {
  1398. // any character other than zero is an exit point
  1399. break;
  1400. }
  1401. }
  1402. this.useExponentialNotation = true;
  1403. return i;
  1404. }
  1405. /**
  1406. * Scan the given string for number patterns, starting
  1407. * from <code>start</code>.
  1408. * This method searches the negative part of the pattern only and scan
  1409. * throught the end of the string.
  1410. *
  1411. * @param pattern The pattern string to parse.
  1412. * @param start The starting parse position in the string.
  1413. */
  1414. private void scanNegativePattern(String pattern,
  1415. DecimalFormatSymbols sourceSymbols,
  1416. int start)
  1417. {
  1418. StringBuilder buffer = new StringBuilder();
  1419. // the number portion is always delimited by one of those
  1420. // characters
  1421. char decimalSeparator = sourceSymbols.getDecimalSeparator();
  1422. char patternSeparator = sourceSymbols.getPatternSeparator();
  1423. char groupingSeparator = sourceSymbols.getGroupingSeparator();
  1424. char digit = sourceSymbols.getDigit();
  1425. char zero = sourceSymbols.getZeroDigit();
  1426. char minus = sourceSymbols.getMinusSign();
  1427. // other special charcaters, cached here to avoid method calls later
  1428. char percent = sourceSymbols.getPercent();
  1429. char permille = sourceSymbols.getPerMill();
  1430. String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol();
  1431. String currencySymbol = CURRENCY_SYMBOL;
  1432. boolean quote = false;
  1433. boolean prefixDone = false;
  1434. int len = pattern.length();
  1435. if (len > 0) this.hasNegativePrefix = true;
  1436. char ch = pattern.charAt(start);
  1437. if (ch == patternSeparator)
  1438. {
  1439. // no pattern separator in the negative pattern
  1440. if ((start + 1) > len) throw new
  1441. IllegalArgumentException("unexpected character '" + ch + "' " +
  1442. "in negative subpattern.");
  1443. start++;
  1444. }
  1445. int i;
  1446. for (i = start; i < len; i++)
  1447. {
  1448. ch = pattern.charAt(i);
  1449. // this means we are inside the number portion
  1450. if (!quote &&
  1451. (ch == digit || ch == zero || ch == decimalSeparator ||
  1452. ch == patternSeparator || ch == groupingSeparator))
  1453. {
  1454. if (!prefixDone)
  1455. {
  1456. this.negativePrefix = buffer.toString();
  1457. buffer.delete(0, buffer.length());
  1458. prefixDone = true;
  1459. }
  1460. }
  1461. else if (ch == minus)
  1462. {
  1463. buffer.append(this.symbols.getMinusSign());
  1464. }
  1465. else if (quote && ch != '\'')
  1466. {
  1467. buffer.append(ch);
  1468. }
  1469. else if (ch == '\u00A4')
  1470. {
  1471. // CURRENCY
  1472. currencySymbol = CURRENCY_SYMBOL;
  1473. // if \u00A4 is doubled, we use the international currency symbol
  1474. if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4')
  1475. {
  1476. currencySymbol = this.symbols.getInternationalCurrencySymbol();
  1477. i = i + 2;
  1478. }
  1479. // FIXME: not sure about this, the specs says that we only have to
  1480. // change prefix and suffix, so leave it as commented
  1481. // unless in case of bug report/errors
  1482. //this.useCurrencySeparator = true;
  1483. buffer.append(currencySymbol);
  1484. }
  1485. else if (ch == percent)
  1486. {
  1487. // PERCENT
  1488. this.negativePatternMultiplier = 100;
  1489. buffer.append(this.symbols.getPercent());
  1490. }
  1491. else if (ch == permille)
  1492. {
  1493. // PERMILLE
  1494. this.negativePatternMultiplier = 1000;
  1495. buffer.append(this.symbols.getPerMill());
  1496. }
  1497. else if (ch == '\'')
  1498. {
  1499. // QUOTE
  1500. if ((i + 1) < len && pattern.charAt(i + 1) == '\'')
  1501. {
  1502. // we need to add ' to the buffer
  1503. buffer.append(ch);
  1504. i++;
  1505. }
  1506. else
  1507. {
  1508. quote = !quote;
  1509. }
  1510. }
  1511. else if (ch == patternSeparator)
  1512. {
  1513. // no pattern separator in the negative pattern
  1514. throw new IllegalArgumentException("unexpected character '" + ch +
  1515. "' in negative subpattern.");
  1516. }
  1517. else
  1518. {
  1519. buffer.append(ch);
  1520. }
  1521. }
  1522. if (prefixDone)
  1523. this.negativeSuffix = buffer.toString();
  1524. else
  1525. this.negativePrefix = buffer.toString();
  1526. }
  1527. /* ****** FORMATTING ****** */
  1528. /**
  1529. * Handles the real formatting.
  1530. *
  1531. * We use a BigDecimal to format the number without precision loss.
  1532. * All the rounding is done by methods in BigDecimal.
  1533. * The <code>isLong</code> parameter is used to determine if we are
  1534. * formatting a long or BigInteger. In this case, we avoid to format
  1535. * the fractional part of the number (unless specified otherwise in the
  1536. * format string) that would consist only of a 0 digit.
  1537. *
  1538. * @param number A BigDecimal representation fo the input number.
  1539. * @param dest The destination buffer.
  1540. * @param isLong A boolean that indicates if this BigDecimal is a real
  1541. * decimal or an integer.
  1542. * @param fieldPos Use to keep track of the formatting position.
  1543. */
  1544. private void formatInternal(BigDecimal number, boolean isLong,
  1545. StringBuffer dest, FieldPosition fieldPos)
  1546. {
  1547. // The specs says that fieldPos should not be null, and that we
  1548. // should throw a NPE, but it seems that in few classes that
  1549. // reference this one, fieldPos is set to null.
  1550. // This is even defined in the javadoc, see for example MessageFormat.
  1551. // I think the best here is to check for fieldPos and build one if it is
  1552. // null. If it cause harms or regressions, just remove this line and
  1553. // fix the classes in the point of call, insted.
  1554. if (fieldPos == null) fieldPos = new FieldPosition(0);
  1555. int _multiplier = this.multiplier;
  1556. // used to track attribute starting position for each attribute
  1557. int attributeStart = -1;
  1558. // now get the sign this will be used by the special case Inifinity
  1559. // and by the normal cases.
  1560. boolean isNegative = (number.signum() < 0) ? true : false;
  1561. if (isNegative)
  1562. {
  1563. attributeStart = dest.length();
  1564. // append the negative prefix to the string
  1565. dest.append(negativePrefix);
  1566. // once got the negative prefix, we can use
  1567. // the absolute value.
  1568. number = number.abs();
  1569. _multiplier = negativePatternMultiplier;
  1570. addAttribute(Field.SIGN, attributeStart, dest.length());
  1571. }
  1572. else
  1573. {
  1574. // not negative, use the positive prefix
  1575. dest.append(positivePrefix);
  1576. }
  1577. // these are used ot update the field position
  1578. int beginIndexInt = dest.length();
  1579. int endIndexInt = 0;
  1580. int beginIndexFract = 0;
  1581. int endIndexFract = 0;
  1582. // compute the multiplier to use with percent and similar
  1583. number = number.multiply(BigDecimal.valueOf(_multiplier));
  1584. // XXX: special case, not sure if it belongs here or if it is
  1585. // correct at all. There may be other special cases as well
  1586. // these should be handled in the format string parser.
  1587. if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0)
  1588. {
  1589. number = BigDecimal.ZERO;
  1590. this.maximumIntegerDigits = 1;
  1591. this.minimumIntegerDigits = 1;
  1592. }
  1593. // get the absolute number
  1594. number = number.abs();
  1595. // the scaling to use while formatting this number
  1596. int scale = this.maximumFractionDigits;
  1597. // this is the actual number we will use
  1598. // it is corrected later on to handle exponential
  1599. // notation, if needed
  1600. long exponent = 0;
  1601. // are we using exponential notation?
  1602. if (this.useExponentialNotation)
  1603. {
  1604. exponent = getExponent(number);
  1605. number = number.movePointLeft((int) exponent);
  1606. // FIXME: this makes the test ##.###E0 to pass,
  1607. // but all all the other tests to fail...
  1608. // this should be really something like
  1609. // min + max - what is already shown...
  1610. //scale = this.minimumIntegerDigits + this.maximumFractionDigits;
  1611. }
  1612. // round the number to the nearest neighbor
  1613. number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
  1614. // now get the integer and fractional part of the string
  1615. // that will be processed later
  1616. String plain = number.toPlainString();
  1617. String intPart = null;
  1618. String fractPart = null;
  1619. // remove - from the integer part, this is needed as
  1620. // the Narrowing Primitive Conversions algorithm used may loose
  1621. // information about the sign
  1622. int minusIndex = plain.lastIndexOf('-', 0);
  1623. if (minusIndex > -1) plain = plain.substring(minusIndex + 1);
  1624. // strip the decimal portion
  1625. int dot = plain.indexOf('.');
  1626. if (dot > -1)
  1627. {
  1628. intPart = plain.substring(0, dot);
  1629. dot++;
  1630. if (useExponentialNotation)
  1631. fractPart = plain.substring(dot, dot + scale);
  1632. else
  1633. fractPart = plain.substring(dot);
  1634. }
  1635. else
  1636. {
  1637. intPart = plain;
  1638. }
  1639. // used in various places later on
  1640. int intPartLen = intPart.length();
  1641. endIndexInt = intPartLen;
  1642. // if the number of digits in our intPart is not greater than the
  1643. // minimum we have to display, we append zero to the destination
  1644. // buffer before adding the integer portion of the number.
  1645. int zeroes = minimumIntegerDigits - intPartLen;
  1646. if (zeroes > 0)
  1647. {
  1648. attributeStart = Math.max(dest.length() - 1, 0);
  1649. appendZero(dest, zeroes, minimumIntegerDigits);
  1650. }
  1651. if (this.useExponentialNotation)
  1652. {
  1653. // For exponential numbers, the significant in mantissa are
  1654. // the sum of the minimum integer and maximum fraction
  1655. // digits, and does not take into account the maximun integer
  1656. // digits to display.
  1657. if (attributeStart < 0)
  1658. attributeStart = Math.max(dest.length() - 1, 0);
  1659. appendDigit(intPart, dest, this.groupingUsed);
  1660. }
  1661. else
  1662. {
  1663. // non exponential notation
  1664. intPartLen = intPart.length();
  1665. int canary = Math.min(intPartLen, this.maximumIntegerDigits);
  1666. // remove from the string the number in excess
  1667. // use only latest digits
  1668. intPart = intPart.substring(intPartLen - canary);
  1669. endIndexInt = intPart.length() + 1;
  1670. // append it
  1671. if (maximumIntegerDigits > 0 &&
  1672. !(this.minimumIntegerDigits == 0 &&
  1673. intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0))
  1674. {
  1675. if (attributeStart < 0)
  1676. attributeStart = Math.max(dest.length() - 1, 0);
  1677. appendDigit(intPart, dest, this.groupingUsed);
  1678. }
  1679. }
  1680. // add the INTEGER attribute
  1681. addAttribute(Field.INTEGER, attributeStart, dest.length());
  1682. // ...update field position, if needed, and return...
  1683. if ((fieldPos.getField() == INTEGER_FIELD ||
  1684. fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
  1685. {
  1686. fieldPos.setBeginIndex(beginIndexInt);
  1687. fieldPos.setEndIndex(endIndexInt);
  1688. }
  1689. handleFractionalPart(dest, fractPart, fieldPos, isLong);
  1690. // and the exponent
  1691. if (this.useExponentialNotation)
  1692. {
  1693. attributeStart = dest.length();
  1694. dest.append(symbols.getExponential());
  1695. addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length());
  1696. attributeStart = dest.length();
  1697. if (exponent < 0)
  1698. {
  1699. dest.append(symbols.getMinusSign());
  1700. exponent = -exponent;
  1701. addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length());
  1702. }
  1703. attributeStart = dest.length();
  1704. String exponentString = String.valueOf(exponent);
  1705. int exponentLength = exponentString.length();
  1706. for (int i = 0; i < minExponentDigits - exponentLength; i++)
  1707. dest.append(symbols.getZeroDigit());
  1708. for (int i = 0; i < exponentLength; ++i)
  1709. dest.append(exponentString.charAt(i));
  1710. addAttribute(Field.EXPONENT, attributeStart, dest.length());
  1711. }
  1712. // now include the suffixes...
  1713. if (isNegative)
  1714. {
  1715. dest.append(negativeSuffix);
  1716. }
  1717. else
  1718. {
  1719. dest.append(positiveSuffix);
  1720. }
  1721. }
  1722. /**
  1723. * Add to the input buffer the result of formatting the fractional
  1724. * portion of the number.
  1725. *
  1726. * @param dest
  1727. * @param fractPart
  1728. * @param fieldPos
  1729. * @param isLong
  1730. */
  1731. private void handleFractionalPart(StringBuffer dest, String fractPart,
  1732. FieldPosition fieldPos, boolean isLong)
  1733. {
  1734. int dotStart = 0;
  1735. int dotEnd = 0;
  1736. boolean addDecimal = false;
  1737. if (this.decimalSeparatorAlwaysShown ||
  1738. ((!isLong || this.useExponentialNotation) &&
  1739. this.showDecimalSeparator && this.maximumFractionDigits > 0) ||
  1740. this.minimumFractionDigits > 0)
  1741. {
  1742. dotStart = dest.length();
  1743. if (this.useCurrencySeparator)
  1744. dest.append(symbols.getMonetaryDecimalSeparator());
  1745. else
  1746. dest.append(symbols.getDecimalSeparator());
  1747. dotEnd = dest.length();
  1748. addDecimal = true;
  1749. }
  1750. // now handle the fraction portion of the number
  1751. int fractStart = 0;
  1752. int fractEnd = 0;
  1753. boolean addFractional = false;
  1754. if ((!isLong || this.useExponentialNotation)
  1755. && this.maximumFractionDigits > 0
  1756. || this.minimumFractionDigits > 0)
  1757. {
  1758. fractStart = dest.length();
  1759. fractEnd = fractStart;
  1760. int digits = this.minimumFractionDigits;
  1761. if (this.useExponentialNotation)
  1762. {
  1763. digits = (this.minimumIntegerDigits + this.minimumFractionDigits)
  1764. - dest.length();
  1765. if (digits < 0) digits = 0;
  1766. }
  1767. fractPart = adjustTrailingZeros(fractPart, digits);
  1768. // FIXME: this code must be improved
  1769. // now check if the factional part is just 0, in this case
  1770. // we need to remove the '.' unless requested
  1771. boolean allZeros = true;
  1772. char fracts[] = fractPart.toCharArray();
  1773. for (int i = 0; i < fracts.length; i++)
  1774. {
  1775. if (fracts[i] != '0')
  1776. allZeros = false;
  1777. }
  1778. if (!allZeros || (minimumFractionDigits > 0))
  1779. {
  1780. appendDigit(fractPart, dest, false);
  1781. fractEnd = dest.length();
  1782. addDecimal = true;
  1783. addFractional = true;
  1784. }
  1785. else if (!this.decimalSeparatorAlwaysShown)
  1786. {
  1787. dest.deleteCharAt(dest.length() - 1);
  1788. addDecimal = false;
  1789. }
  1790. else
  1791. {
  1792. fractEnd = dest.length();
  1793. addFractional = true;
  1794. }
  1795. }
  1796. if (addDecimal)
  1797. addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd);
  1798. if (addFractional)
  1799. addAttribute(Field.FRACTION, fractStart, fractEnd);
  1800. if ((fieldPos.getField() == FRACTION_FIELD ||
  1801. fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION))
  1802. {
  1803. fieldPos.setBeginIndex(fractStart);
  1804. fieldPos.setEndIndex(fractEnd);
  1805. }
  1806. }
  1807. /**
  1808. * Append to <code>dest</code>the give number of zeros.
  1809. * Grouping is added if needed.
  1810. * The integer totalDigitCount defines the total number of digits
  1811. * of the number to which we are appending zeroes.
  1812. */
  1813. private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount)
  1814. {
  1815. char ch = symbols.getZeroDigit();
  1816. char gSeparator = symbols.getGroupingSeparator();
  1817. int i = 0;
  1818. int gPos = totalDigitCount;
  1819. for (i = 0; i < zeroes; i++, gPos--)
  1820. {
  1821. if (this.groupingSeparatorInPattern &&
  1822. (this.groupingUsed && this.groupingSize != 0) &&
  1823. (gPos % groupingSize == 0 && i > 0))
  1824. dest.append(gSeparator);
  1825. dest.append(ch);
  1826. }
  1827. // special case, that requires adding an additional separator
  1828. if (this.groupingSeparatorInPattern &&
  1829. (this.groupingUsed && this.groupingSize != 0) &&
  1830. (gPos % groupingSize == 0))
  1831. dest.append(gSeparator);
  1832. }
  1833. /**
  1834. * Append src to <code>dest</code>.
  1835. *
  1836. * Grouping is added if <code>groupingUsed</code> is set
  1837. * to <code>true</code>.
  1838. */
  1839. private void appendDigit(String src, StringBuffer dest,
  1840. boolean groupingUsed)
  1841. {
  1842. int zero = symbols.getZeroDigit() - '0';
  1843. int ch;
  1844. char gSeparator = symbols.getGroupingSeparator();
  1845. int len = src.length();
  1846. for (int i = 0, gPos = len; i < len; i++, gPos--)
  1847. {
  1848. ch = src.charAt(i);
  1849. if (groupingUsed && this.groupingSize != 0 &&
  1850. gPos % groupingSize == 0 && i > 0)
  1851. dest.append(gSeparator);
  1852. dest.append((char) (zero + ch));
  1853. }
  1854. }
  1855. /**
  1856. * Calculate the exponent to use if eponential notation is used.
  1857. * The exponent is calculated as a power of ten.
  1858. * <code>number</code> should be positive, if is zero, or less than zero,
  1859. * zero is returned.
  1860. */
  1861. private long getExponent(BigDecimal number)
  1862. {
  1863. long exponent = 0;
  1864. if (number.signum() > 0)
  1865. {
  1866. double _number = number.doubleValue();
  1867. exponent = (long) Math.floor (Math.log10(_number));
  1868. // get the right value for the exponent
  1869. exponent = exponent - (exponent % this.exponentRound);
  1870. // if the minimumIntegerDigits is more than zero
  1871. // we display minimumIntegerDigits of digits.
  1872. // so, for example, if minimumIntegerDigits == 2
  1873. // and the actual number is 0.123 it will be
  1874. // formatted as 12.3E-2
  1875. // this means that the exponent have to be shifted
  1876. // to the correct value.
  1877. if (minimumIntegerDigits > 0)
  1878. exponent -= minimumIntegerDigits - 1;
  1879. }
  1880. return exponent;
  1881. }
  1882. /**
  1883. * Remove contiguos zeros from the end of the <code>src</code> string,
  1884. * if src contains more than <code>minimumDigits</code> digits.
  1885. * if src contains less that <code>minimumDigits</code>,
  1886. * then append zeros to the string.
  1887. *
  1888. * Only the first block of zero digits is removed from the string
  1889. * and only if they fall in the src.length - minimumDigits
  1890. * portion of the string.
  1891. *
  1892. * @param src The string with the correct number of zeros.
  1893. */
  1894. private String adjustTrailingZeros(String src, int minimumDigits)
  1895. {
  1896. int len = src.length();
  1897. String result;
  1898. // remove all trailing zero
  1899. if (len > minimumDigits)
  1900. {
  1901. int zeros = 0;
  1902. for (int i = len - 1; i > minimumDigits; i--)
  1903. {
  1904. if (src.charAt(i) == '0')
  1905. ++zeros;
  1906. else
  1907. break;
  1908. }
  1909. result = src.substring(0, len - zeros);
  1910. }
  1911. else
  1912. {
  1913. char zero = symbols.getZeroDigit();
  1914. CPStringBuilder _result = new CPStringBuilder(src);
  1915. for (int i = len; i < minimumDigits; i++)
  1916. {
  1917. _result.append(zero);
  1918. }
  1919. result = _result.toString();
  1920. }
  1921. return result;
  1922. }
  1923. /**
  1924. * Adds an attribute to the attributes list.
  1925. *
  1926. * @param field
  1927. * @param begin
  1928. * @param end
  1929. */
  1930. private void addAttribute(Field field, int begin, int end)
  1931. {
  1932. /*
  1933. * This method and its implementation derives directly from the
  1934. * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X.
  1935. */
  1936. FieldPosition pos = new FieldPosition(field);
  1937. pos.setBeginIndex(begin);
  1938. pos.setEndIndex(end);
  1939. attributes.add(pos);
  1940. }
  1941. /**
  1942. * Sets the default values for the various properties in this DecimaFormat.
  1943. */
  1944. private void setDefaultValues()
  1945. {
  1946. // Maybe we should add these values to the message bundle and take
  1947. // the most appropriate for them for any locale.
  1948. // Anyway, these seem to be good values for a default in most languages.
  1949. // Note that most of these will change based on the format string.
  1950. this.negativePrefix = String.valueOf(symbols.getMinusSign());
  1951. this.negativeSuffix = "";
  1952. this.positivePrefix = "";
  1953. this.positiveSuffix = "";
  1954. this.multiplier = 1;
  1955. this.negativePatternMultiplier = 1;
  1956. this.exponentRound = 1;
  1957. this.hasNegativePrefix = false;
  1958. this.minimumIntegerDigits = 1;
  1959. this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS;
  1960. this.minimumFractionDigits = 0;
  1961. this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS;
  1962. this.minExponentDigits = 0;
  1963. this.groupingSize = 0;
  1964. this.decimalSeparatorAlwaysShown = false;
  1965. this.showDecimalSeparator = false;
  1966. this.useExponentialNotation = false;
  1967. this.groupingUsed = false;
  1968. this.groupingSeparatorInPattern = false;
  1969. this.useCurrencySeparator = false;
  1970. this.hasFractionalPattern = false;
  1971. }
  1972. }