~ubuntu-branches/ubuntu/karmic/commons-math/karmic

« back to all changes in this revision

Viewing changes to src/java/org/apache/commons/math/fraction/ProperFractionFormat.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-03-15 20:20:21 UTC
  • Revision ID: james.westby@ubuntu.com-20090315202021-zto3nmvqgcf3ami4
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 *      http://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
package org.apache.commons.math.fraction;
 
18
 
 
19
import java.text.FieldPosition;
 
20
import java.text.NumberFormat;
 
21
import java.text.ParsePosition;
 
22
 
 
23
import org.apache.commons.math.util.MathUtils;
 
24
 
 
25
/**
 
26
 * Formats a Fraction number in proper format.  The number format for each of
 
27
 * the whole number, numerator and, denominator can be configured.
 
28
 * <p>
 
29
 * Minus signs are only allowed in the whole number part - i.e.,
 
30
 * "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
 
31
 * will result in a <code>ParseException</code>.</p>
 
32
 * 
 
33
 * @since 1.1
 
34
 * @version $Revision: 617953 $ $Date: 2008-02-02 22:54:00 -0700 (Sat, 02 Feb 2008) $
 
35
 */
 
36
public class ProperFractionFormat extends FractionFormat {
 
37
    
 
38
    /** Serializable version identifier */
 
39
    private static final long serialVersionUID = -6337346779577272307L;
 
40
    
 
41
    /** The format used for the whole number. */
 
42
    private NumberFormat wholeFormat;
 
43
 
 
44
    /**
 
45
     * Create a proper formatting instance with the default number format for
 
46
     * the whole, numerator, and denominator.  
 
47
     */
 
48
    public ProperFractionFormat() {
 
49
        this(getDefaultNumberFormat());
 
50
    }
 
51
    
 
52
    /**
 
53
     * Create a proper formatting instance with a custom number format for the
 
54
     * whole, numerator, and denominator.
 
55
     * @param format the custom format for the whole, numerator, and
 
56
     *        denominator.
 
57
     */
 
58
    public ProperFractionFormat(NumberFormat format) {
 
59
        this(format, (NumberFormat)format.clone(), (NumberFormat)format.clone());
 
60
    }
 
61
    
 
62
    /**
 
63
     * Create a proper formatting instance with a custom number format for each
 
64
     * of the whole, numerator, and denominator.
 
65
     * @param wholeFormat the custom format for the whole.
 
66
     * @param numeratorFormat the custom format for the numerator.
 
67
     * @param denominatorFormat the custom format for the denominator.
 
68
     */
 
69
    public ProperFractionFormat(NumberFormat wholeFormat,
 
70
            NumberFormat numeratorFormat,
 
71
            NumberFormat denominatorFormat)
 
72
    {
 
73
        super(numeratorFormat, denominatorFormat);
 
74
        setWholeFormat(wholeFormat);
 
75
    }
 
76
    
 
77
    /**
 
78
     * Formats a {@link Fraction} object to produce a string.  The fraction
 
79
     * is output in proper format.
 
80
     *
 
81
     * @param fraction the object to format.
 
82
     * @param toAppendTo where the text is to be appended
 
83
     * @param pos On input: an alignment field, if desired. On output: the
 
84
     *            offsets of the alignment field
 
85
     * @return the value passed in as toAppendTo.
 
86
     */
 
87
    public StringBuffer format(Fraction fraction, StringBuffer toAppendTo,
 
88
            FieldPosition pos) {
 
89
        
 
90
        pos.setBeginIndex(0);
 
91
        pos.setEndIndex(0);
 
92
 
 
93
        int num = fraction.getNumerator();
 
94
        int den = fraction.getDenominator();
 
95
        int whole = num / den;
 
96
        num = num % den;
 
97
        
 
98
        if (whole != 0) {
 
99
            getWholeFormat().format(whole, toAppendTo, pos);
 
100
            toAppendTo.append(' ');
 
101
            num = Math.abs(num);
 
102
        }
 
103
        getNumeratorFormat().format(num, toAppendTo, pos);
 
104
        toAppendTo.append(" / ");
 
105
        getDenominatorFormat().format(den, toAppendTo,
 
106
            pos);
 
107
        
 
108
        return toAppendTo;
 
109
    }
 
110
 
 
111
    /**
 
112
     * Access the whole format.
 
113
     * @return the whole format.
 
114
     */
 
115
    public NumberFormat getWholeFormat() {
 
116
        return wholeFormat;
 
117
    }
 
118
    
 
119
    /**
 
120
     * Parses a string to produce a {@link Fraction} object.  This method
 
121
     * expects the string to be formatted as a proper fraction.
 
122
     * <p>
 
123
     * Minus signs are only allowed in the whole number part - i.e.,
 
124
     * "-3 1/2" is legitimate and denotes -7/2, but "-3 -1/2" is invalid and
 
125
     * will result in a <code>ParseException</code>.</p>
 
126
     * 
 
127
     * @param source the string to parse
 
128
     * @param pos input/ouput parsing parameter.
 
129
     * @return the parsed {@link Fraction} object.
 
130
     */
 
131
    public Fraction parse(String source, ParsePosition pos) {
 
132
        // try to parse improper fraction
 
133
        Fraction ret = super.parse(source, pos);
 
134
        if (ret != null) {
 
135
            return ret;
 
136
        }
 
137
        
 
138
        int initialIndex = pos.getIndex();
 
139
 
 
140
        // parse whitespace
 
141
        parseAndIgnoreWhitespace(source, pos);
 
142
 
 
143
        // parse whole
 
144
        Number whole = getWholeFormat().parse(source, pos);
 
145
        if (whole == null) {
 
146
            // invalid integer number
 
147
            // set index back to initial, error index should already be set
 
148
            // character examined.
 
149
            pos.setIndex(initialIndex);
 
150
            return null;
 
151
        }
 
152
 
 
153
        // parse whitespace
 
154
        parseAndIgnoreWhitespace(source, pos);
 
155
        
 
156
        // parse numerator
 
157
        Number num = getNumeratorFormat().parse(source, pos);
 
158
        if (num == null) {
 
159
            // invalid integer number
 
160
            // set index back to initial, error index should already be set
 
161
            // character examined.
 
162
            pos.setIndex(initialIndex);
 
163
            return null;
 
164
        }
 
165
        
 
166
        if (num.intValue() < 0) {
 
167
            // minus signs should be leading, invalid expression
 
168
            pos.setIndex(initialIndex);
 
169
            return null;
 
170
        }
 
171
 
 
172
        // parse '/'
 
173
        int startIndex = pos.getIndex();
 
174
        char c = parseNextCharacter(source, pos);
 
175
        switch (c) {
 
176
        case 0 :
 
177
            // no '/'
 
178
            // return num as a fraction
 
179
            return new Fraction(num.intValue(), 1);
 
180
        case '/' :
 
181
            // found '/', continue parsing denominator
 
182
            break;
 
183
        default :
 
184
            // invalid '/'
 
185
            // set index back to initial, error index should be the last
 
186
            // character examined.
 
187
            pos.setIndex(initialIndex);
 
188
            pos.setErrorIndex(startIndex);
 
189
            return null;
 
190
        }
 
191
 
 
192
        // parse whitespace
 
193
        parseAndIgnoreWhitespace(source, pos);
 
194
 
 
195
        // parse denominator
 
196
        Number den = getDenominatorFormat().parse(source, pos);
 
197
        if (den == null) {
 
198
            // invalid integer number
 
199
            // set index back to initial, error index should already be set
 
200
            // character examined.
 
201
            pos.setIndex(initialIndex);
 
202
            return null;
 
203
        }
 
204
        
 
205
        if (den.intValue() < 0) {
 
206
            // minus signs must be leading, invalid
 
207
            pos.setIndex(initialIndex);
 
208
            return null;
 
209
        }
 
210
 
 
211
        int w = whole.intValue();
 
212
        int n = num.intValue();
 
213
        int d = den.intValue();
 
214
        return new Fraction(((Math.abs(w) * d) + n) * MathUtils.sign(w), d);
 
215
    }
 
216
    
 
217
    /**
 
218
     * Modify the whole format.
 
219
     * @param format The new whole format value.
 
220
     * @throws IllegalArgumentException if <code>format</code> is
 
221
     *         <code>null</code>.
 
222
     */
 
223
    public void setWholeFormat(NumberFormat format) {
 
224
        if (format == null) {
 
225
            throw new IllegalArgumentException(
 
226
                "whole format can not be null.");
 
227
        }
 
228
        this.wholeFormat = format;
 
229
    }
 
230
}