View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.fraction;
24  
25  import java.io.Serializable;
26  import java.math.BigInteger;
27  import java.text.FieldPosition;
28  import java.text.NumberFormat;
29  import java.text.ParsePosition;
30  import java.util.Locale;
31  
32  import org.hipparchus.exception.LocalizedCoreFormats;
33  import org.hipparchus.exception.MathIllegalArgumentException;
34  import org.hipparchus.exception.MathIllegalStateException;
35  
36  /**
37   * Formats a BigFraction number in proper format or improper format.
38   * <p>
39   * The number format for each of the whole number, numerator and,
40   * denominator can be configured.
41   */
42  public class BigFractionFormat extends AbstractFormat implements Serializable {
43  
44      /** Serializable version identifier */
45      private static final long serialVersionUID = 20160323L;
46  
47      /**
48       * Create an improper formatting instance with the default number format
49       * for the numerator and denominator.
50       */
51      public BigFractionFormat() {
52          // This constructor is intentionally empty. Nothing special is needed here.
53      }
54  
55      /**
56       * Create an improper formatting instance with a custom number format for
57       * both the numerator and denominator.
58       * @param format the custom format for both the numerator and denominator.
59       * @throws org.hipparchus.exception.NullArgumentException if the provided format is null.
60       */
61      public BigFractionFormat(final NumberFormat format) {
62          super(format);
63      }
64  
65      /**
66       * Create an improper formatting instance with a custom number format for
67       * the numerator and a custom number format for the denominator.
68       * @param numeratorFormat the custom format for the numerator.
69       * @param denominatorFormat the custom format for the denominator.
70       * @throws org.hipparchus.exception.NullArgumentException if either provided format is null.
71       */
72      public BigFractionFormat(final NumberFormat numeratorFormat,
73                               final NumberFormat denominatorFormat) {
74          super(numeratorFormat, denominatorFormat);
75      }
76  
77      /**
78       * Get the set of locales for which complex formats are available.  This
79       * is the same set as the {@link NumberFormat} set.
80       * @return available complex format locales.
81       */
82      public static Locale[] getAvailableLocales() {
83          return NumberFormat.getAvailableLocales();
84      }
85  
86      /**
87       * This static method calls formatBigFraction() on a default instance of
88       * BigFractionFormat.
89       *
90       * @param f BigFraction object to format
91       * @return A formatted BigFraction in proper form.
92       */
93      public static String formatBigFraction(final BigFraction f) {
94          return getImproperInstance().format(f);
95      }
96  
97      /**
98       * Returns the default complex format for the current locale.
99       * @return the default complex format.
100      */
101     public static BigFractionFormat getImproperInstance() {
102         return getImproperInstance(Locale.getDefault());
103     }
104 
105     /**
106      * Returns the default complex format for the given locale.
107      * @param locale the specific locale used by the format.
108      * @return the complex format specific to the given locale.
109      */
110     public static BigFractionFormat getImproperInstance(final Locale locale) {
111         return new BigFractionFormat(getDefaultNumberFormat(locale));
112     }
113 
114     /**
115      * Returns the default complex format for the current locale.
116      * @return the default complex format.
117      */
118     public static BigFractionFormat getProperInstance() {
119         return getProperInstance(Locale.getDefault());
120     }
121 
122     /**
123      * Returns the default complex format for the given locale.
124      * @param locale the specific locale used by the format.
125      * @return the complex format specific to the given locale.
126      */
127     public static BigFractionFormat getProperInstance(final Locale locale) {
128         return new ProperBigFractionFormat(getDefaultNumberFormat(locale));
129     }
130 
131     /**
132      * Formats a {@link BigFraction} object to produce a string.  The BigFraction is
133      * output in improper format.
134      *
135      * @param BigFraction the object to format.
136      * @param toAppendTo where the text is to be appended
137      * @param pos On input: an alignment field, if desired. On output: the
138      *            offsets of the alignment field
139      * @return the value passed in as toAppendTo.
140      */
141     public StringBuffer format(final BigFraction BigFraction, // NOPMD - PMD false positive, we cannot have @Override here
142                                final StringBuffer toAppendTo, final FieldPosition pos) {
143 
144         pos.setBeginIndex(0);
145         pos.setEndIndex(0);
146 
147         getNumeratorFormat().format(BigFraction.getNumerator(), toAppendTo, pos);
148         toAppendTo.append(" / ");
149         getDenominatorFormat().format(BigFraction.getDenominator(), toAppendTo, pos);
150 
151         return toAppendTo;
152     }
153 
154     /**
155      * Formats an object and appends the result to a StringBuffer.
156      * <code>obj</code> must be either a  {@link BigFraction} object or a
157      * {@link BigInteger} object or a {@link Number} object. Any other type of
158      * object will result in an {@link IllegalArgumentException} being thrown.
159      *
160      * @param obj the object to format.
161      * @param toAppendTo where the text is to be appended
162      * @param pos On input: an alignment field, if desired. On output: the
163      *            offsets of the alignment field
164      * @return the value passed in as toAppendTo.
165      * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
166      * @throws MathIllegalArgumentException if <code>obj</code> is not a valid type.
167      */
168     @Override
169     public StringBuffer format(final Object obj,
170                                final StringBuffer toAppendTo, final FieldPosition pos) {
171 
172         final StringBuffer ret;
173         if (obj instanceof BigFraction) {
174             ret = format((BigFraction) obj, toAppendTo, pos);
175         } else if (obj instanceof BigInteger) {
176             ret = format(new BigFraction((BigInteger) obj), toAppendTo, pos);
177         } else if (obj instanceof Number) {
178             ret = format(new BigFraction(((Number) obj).doubleValue()),
179                          toAppendTo, pos);
180         } else {
181             throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_FORMAT_OBJECT_TO_FRACTION);
182         }
183 
184         return ret;
185     }
186 
187     /**
188      * Parses a string to produce a {@link BigFraction} object.
189      * @param source the string to parse
190      * @return the parsed {@link BigFraction} object.
191      * @exception MathIllegalStateException if the beginning of the specified string
192      *            cannot be parsed.
193      */
194     @Override
195     public BigFraction parse(final String source) throws MathIllegalStateException {
196         final ParsePosition parsePosition = new ParsePosition(0);
197         final BigFraction result = parse(source, parsePosition);
198         if (parsePosition.getIndex() == 0) {
199             throw new MathIllegalStateException(LocalizedCoreFormats.CANNOT_PARSE_AS_TYPE,
200                                                 source, parsePosition.getErrorIndex(),
201                                                 BigFraction.class);
202         }
203         return result;
204     }
205 
206     /**
207      * Parses a string to produce a {@link BigFraction} object.
208      * This method expects the string to be formatted as an improper BigFraction.
209      * @param source the string to parse
210      * @param pos input/output parsing parameter.
211      * @return the parsed {@link BigFraction} object.
212      */
213     @Override
214     public BigFraction parse(final String source, final ParsePosition pos) {
215         final int initialIndex = pos.getIndex();
216 
217         // parse whitespace
218         parseAndIgnoreWhitespace(source, pos);
219 
220         // parse numerator
221         final BigInteger num = parseNextBigInteger(source, pos);
222         if (num == null) {
223             // invalid integer number
224             // set index back to initial, error index should already be set
225             // character examined.
226             pos.setIndex(initialIndex);
227             return null;
228         }
229 
230         // parse '/'
231         final int startIndex = pos.getIndex();
232         final char c = parseNextCharacter(source, pos);
233         switch (c) {
234         case 0 :
235             // no '/'
236             // return num as a BigFraction
237             return new BigFraction(num);
238         case '/' :
239             // found '/', continue parsing denominator
240             break;
241         default :
242             // invalid '/'
243             // set index back to initial, error index should be the last
244             // character examined.
245             pos.setIndex(initialIndex);
246             pos.setErrorIndex(startIndex);
247             return null;
248         }
249 
250         // parse whitespace
251         parseAndIgnoreWhitespace(source, pos);
252 
253         // parse denominator
254         final BigInteger den = parseNextBigInteger(source, pos);
255         if (den == null) {
256             // invalid integer number
257             // set index back to initial, error index should already be set
258             // character examined.
259             pos.setIndex(initialIndex);
260             return null;
261         }
262 
263         return new BigFraction(num, den);
264     }
265 
266     /**
267      * Parses a string to produce a <code>BigInteger</code>.
268      * @param source the string to parse
269      * @param pos input/output parsing parameter.
270      * @return a parsed <code>BigInteger</code> or null if string does not
271      * contain a BigInteger at the specified position
272      */
273     protected BigInteger parseNextBigInteger(final String source,
274                                              final ParsePosition pos) {
275 
276         final int start = pos.getIndex();
277          int end = (source.charAt(start) == '-') ? (start + 1) : start;
278          while((end < source.length()) &&
279                Character.isDigit(source.charAt(end))) {
280              ++end;
281          }
282 
283          try {
284              BigInteger n = new BigInteger(source.substring(start, end));
285              pos.setIndex(end);
286              return n;
287          } catch (NumberFormatException nfe) {
288              pos.setErrorIndex(start);
289              return null;
290          }
291 
292     }
293 
294 }