BigFractionFormat.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.fraction;

  22. import java.io.Serializable;
  23. import java.math.BigInteger;
  24. import java.text.FieldPosition;
  25. import java.text.NumberFormat;
  26. import java.text.ParsePosition;
  27. import java.util.Locale;

  28. import org.hipparchus.exception.LocalizedCoreFormats;
  29. import org.hipparchus.exception.MathIllegalArgumentException;
  30. import org.hipparchus.exception.MathIllegalStateException;

  31. /**
  32.  * Formats a BigFraction number in proper format or improper format.
  33.  * <p>
  34.  * The number format for each of the whole number, numerator and,
  35.  * denominator can be configured.
  36.  */
  37. public class BigFractionFormat extends AbstractFormat implements Serializable {

  38.     /** Serializable version identifier */
  39.     private static final long serialVersionUID = 20160323L;

  40.     /**
  41.      * Create an improper formatting instance with the default number format
  42.      * for the numerator and denominator.
  43.      */
  44.     public BigFractionFormat() {
  45.         // This constructor is intentionally empty. Nothing special is needed here.
  46.     }

  47.     /**
  48.      * Create an improper formatting instance with a custom number format for
  49.      * both the numerator and denominator.
  50.      * @param format the custom format for both the numerator and denominator.
  51.      * @throws org.hipparchus.exception.NullArgumentException if the provided format is null.
  52.      */
  53.     public BigFractionFormat(final NumberFormat format) {
  54.         super(format);
  55.     }

  56.     /**
  57.      * Create an improper formatting instance with a custom number format for
  58.      * the numerator and a custom number format for the denominator.
  59.      * @param numeratorFormat the custom format for the numerator.
  60.      * @param denominatorFormat the custom format for the denominator.
  61.      * @throws org.hipparchus.exception.NullArgumentException if either provided format is null.
  62.      */
  63.     public BigFractionFormat(final NumberFormat numeratorFormat,
  64.                              final NumberFormat denominatorFormat) {
  65.         super(numeratorFormat, denominatorFormat);
  66.     }

  67.     /**
  68.      * Get the set of locales for which complex formats are available.  This
  69.      * is the same set as the {@link NumberFormat} set.
  70.      * @return available complex format locales.
  71.      */
  72.     public static Locale[] getAvailableLocales() {
  73.         return NumberFormat.getAvailableLocales();
  74.     }

  75.     /**
  76.      * This static method calls formatBigFraction() on a default instance of
  77.      * BigFractionFormat.
  78.      *
  79.      * @param f BigFraction object to format
  80.      * @return A formatted BigFraction in proper form.
  81.      */
  82.     public static String formatBigFraction(final BigFraction f) {
  83.         return getImproperInstance().format(f);
  84.     }

  85.     /**
  86.      * Returns the default complex format for the current locale.
  87.      * @return the default complex format.
  88.      */
  89.     public static BigFractionFormat getImproperInstance() {
  90.         return getImproperInstance(Locale.getDefault());
  91.     }

  92.     /**
  93.      * Returns the default complex format for the given locale.
  94.      * @param locale the specific locale used by the format.
  95.      * @return the complex format specific to the given locale.
  96.      */
  97.     public static BigFractionFormat getImproperInstance(final Locale locale) {
  98.         return new BigFractionFormat(getDefaultNumberFormat(locale));
  99.     }

  100.     /**
  101.      * Returns the default complex format for the current locale.
  102.      * @return the default complex format.
  103.      */
  104.     public static BigFractionFormat getProperInstance() {
  105.         return getProperInstance(Locale.getDefault());
  106.     }

  107.     /**
  108.      * Returns the default complex format for the given locale.
  109.      * @param locale the specific locale used by the format.
  110.      * @return the complex format specific to the given locale.
  111.      */
  112.     public static BigFractionFormat getProperInstance(final Locale locale) {
  113.         return new ProperBigFractionFormat(getDefaultNumberFormat(locale));
  114.     }

  115.     /**
  116.      * Formats a {@link BigFraction} object to produce a string.  The BigFraction is
  117.      * output in improper format.
  118.      *
  119.      * @param BigFraction the object to format.
  120.      * @param toAppendTo where the text is to be appended
  121.      * @param pos On input: an alignment field, if desired. On output: the
  122.      *            offsets of the alignment field
  123.      * @return the value passed in as toAppendTo.
  124.      */
  125.     public StringBuffer format(final BigFraction BigFraction, // NOPMD - PMD false positive, we cannot have @Override here
  126.                                final StringBuffer toAppendTo, final FieldPosition pos) {

  127.         pos.setBeginIndex(0);
  128.         pos.setEndIndex(0);

  129.         getNumeratorFormat().format(BigFraction.getNumerator(), toAppendTo, pos);
  130.         toAppendTo.append(" / ");
  131.         getDenominatorFormat().format(BigFraction.getDenominator(), toAppendTo, pos);

  132.         return toAppendTo;
  133.     }

  134.     /**
  135.      * Formats an object and appends the result to a StringBuffer.
  136.      * <code>obj</code> must be either a  {@link BigFraction} object or a
  137.      * {@link BigInteger} object or a {@link Number} object. Any other type of
  138.      * object will result in an {@link IllegalArgumentException} being thrown.
  139.      *
  140.      * @param obj the object to format.
  141.      * @param toAppendTo where the text is to be appended
  142.      * @param pos On input: an alignment field, if desired. On output: the
  143.      *            offsets of the alignment field
  144.      * @return the value passed in as toAppendTo.
  145.      * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
  146.      * @throws MathIllegalArgumentException if <code>obj</code> is not a valid type.
  147.      */
  148.     @Override
  149.     public StringBuffer format(final Object obj,
  150.                                final StringBuffer toAppendTo, final FieldPosition pos) {

  151.         final StringBuffer ret;
  152.         if (obj instanceof BigFraction) {
  153.             ret = format((BigFraction) obj, toAppendTo, pos);
  154.         } else if (obj instanceof BigInteger) {
  155.             ret = format(new BigFraction((BigInteger) obj), toAppendTo, pos);
  156.         } else if (obj instanceof Number) {
  157.             ret = format(new BigFraction(((Number) obj).doubleValue()),
  158.                          toAppendTo, pos);
  159.         } else {
  160.             throw new MathIllegalArgumentException(LocalizedCoreFormats.CANNOT_FORMAT_OBJECT_TO_FRACTION);
  161.         }

  162.         return ret;
  163.     }

  164.     /**
  165.      * Parses a string to produce a {@link BigFraction} object.
  166.      * @param source the string to parse
  167.      * @return the parsed {@link BigFraction} object.
  168.      * @exception MathIllegalStateException if the beginning of the specified string
  169.      *            cannot be parsed.
  170.      */
  171.     @Override
  172.     public BigFraction parse(final String source) throws MathIllegalStateException {
  173.         final ParsePosition parsePosition = new ParsePosition(0);
  174.         final BigFraction result = parse(source, parsePosition);
  175.         if (parsePosition.getIndex() == 0) {
  176.             throw new MathIllegalStateException(LocalizedCoreFormats.CANNOT_PARSE_AS_TYPE,
  177.                                                 source, parsePosition.getErrorIndex(),
  178.                                                 BigFraction.class);
  179.         }
  180.         return result;
  181.     }

  182.     /**
  183.      * Parses a string to produce a {@link BigFraction} object.
  184.      * This method expects the string to be formatted as an improper BigFraction.
  185.      * @param source the string to parse
  186.      * @param pos input/output parsing parameter.
  187.      * @return the parsed {@link BigFraction} object.
  188.      */
  189.     @Override
  190.     public BigFraction parse(final String source, final ParsePosition pos) {
  191.         final int initialIndex = pos.getIndex();

  192.         // parse whitespace
  193.         parseAndIgnoreWhitespace(source, pos);

  194.         // parse numerator
  195.         final BigInteger num = parseNextBigInteger(source, pos);
  196.         if (num == null) {
  197.             // invalid integer number
  198.             // set index back to initial, error index should already be set
  199.             // character examined.
  200.             pos.setIndex(initialIndex);
  201.             return null;
  202.         }

  203.         // parse '/'
  204.         final int startIndex = pos.getIndex();
  205.         final char c = parseNextCharacter(source, pos);
  206.         switch (c) {
  207.         case 0 :
  208.             // no '/'
  209.             // return num as a BigFraction
  210.             return new BigFraction(num);
  211.         case '/' :
  212.             // found '/', continue parsing denominator
  213.             break;
  214.         default :
  215.             // invalid '/'
  216.             // set index back to initial, error index should be the last
  217.             // character examined.
  218.             pos.setIndex(initialIndex);
  219.             pos.setErrorIndex(startIndex);
  220.             return null;
  221.         }

  222.         // parse whitespace
  223.         parseAndIgnoreWhitespace(source, pos);

  224.         // parse denominator
  225.         final BigInteger den = parseNextBigInteger(source, pos);
  226.         if (den == null) {
  227.             // invalid integer number
  228.             // set index back to initial, error index should already be set
  229.             // character examined.
  230.             pos.setIndex(initialIndex);
  231.             return null;
  232.         }

  233.         return new BigFraction(num, den);
  234.     }

  235.     /**
  236.      * Parses a string to produce a <code>BigInteger</code>.
  237.      * @param source the string to parse
  238.      * @param pos input/output parsing parameter.
  239.      * @return a parsed <code>BigInteger</code> or null if string does not
  240.      * contain a BigInteger at the specified position
  241.      */
  242.     protected BigInteger parseNextBigInteger(final String source,
  243.                                              final ParsePosition pos) {

  244.         final int start = pos.getIndex();
  245.          int end = (source.charAt(start) == '-') ? (start + 1) : start;
  246.          while((end < source.length()) &&
  247.                Character.isDigit(source.charAt(end))) {
  248.              ++end;
  249.          }

  250.          try {
  251.              BigInteger n = new BigInteger(source.substring(start, end));
  252.              pos.setIndex(end);
  253.              return n;
  254.          } catch (NumberFormatException nfe) {
  255.              pos.setErrorIndex(start);
  256.              return null;
  257.          }

  258.     }

  259. }