diff options
Diffstat (limited to 'src/main/java/org/apache/commons/math/util/CompositeFormat.java')
-rw-r--r-- | src/main/java/org/apache/commons/math/util/CompositeFormat.java | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/util/CompositeFormat.java b/src/main/java/org/apache/commons/math/util/CompositeFormat.java new file mode 100644 index 0000000..99d18ab --- /dev/null +++ b/src/main/java/org/apache/commons/math/util/CompositeFormat.java @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.util; + +import java.text.FieldPosition; +import java.text.Format; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * Base class for formatters of composite objects (complex numbers, vectors ...). + * + * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $ + */ +public abstract class CompositeFormat extends Format { + + /** Serializable version identifier. */ + private static final long serialVersionUID = 5358685519349262494L; + + /** + * Create a default number format. The default number format is based on + * {@link NumberFormat#getInstance()} with the only customizing that the + * maximum number of fraction digits is set to 2. + * @return the default number format. + */ + protected static NumberFormat getDefaultNumberFormat() { + return getDefaultNumberFormat(Locale.getDefault()); + } + + /** + * Create a default number format. The default number format is based on + * {@link NumberFormat#getInstance(java.util.Locale)} with the only + * customizing that the maximum number of fraction digits is set to 2. + * @param locale the specific locale used by the format. + * @return the default number format specific to the given locale. + */ + protected static NumberFormat getDefaultNumberFormat(final Locale locale) { + final NumberFormat nf = NumberFormat.getInstance(locale); + nf.setMaximumFractionDigits(2); + return nf; + } + + /** + * Parses <code>source</code> until a non-whitespace character is found. + * + * @param source the string to parse + * @param pos input/ouput parsing parameter. On output, <code>pos</code> + * holds the index of the next non-whitespace character. + */ + protected void parseAndIgnoreWhitespace(final String source, + final ParsePosition pos) { + parseNextCharacter(source, pos); + pos.setIndex(pos.getIndex() - 1); + } + + /** + * Parses <code>source</code> until a non-whitespace character is found. + * + * @param source the string to parse + * @param pos input/ouput parsing parameter. + * @return the first non-whitespace character. + */ + protected char parseNextCharacter(final String source, + final ParsePosition pos) { + int index = pos.getIndex(); + final int n = source.length(); + char ret = 0; + + if (index < n) { + char c; + do { + c = source.charAt(index++); + } while (Character.isWhitespace(c) && index < n); + pos.setIndex(index); + + if (index < n) { + ret = c; + } + } + + return ret; + } + + /** + * Parses <code>source</code> for special double values. These values + * include Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY. + * + * @param source the string to parse + * @param value the special value to parse. + * @param pos input/ouput parsing parameter. + * @return the special number. + */ + private Number parseNumber(final String source, final double value, + final ParsePosition pos) { + Number ret = null; + + StringBuilder sb = new StringBuilder(); + sb.append('('); + sb.append(value); + sb.append(')'); + + final int n = sb.length(); + final int startIndex = pos.getIndex(); + final int endIndex = startIndex + n; + if (endIndex < source.length()) { + if (source.substring(startIndex, endIndex).compareTo(sb.toString()) == 0) { + ret = Double.valueOf(value); + pos.setIndex(endIndex); + } + } + + return ret; + } + + /** + * Parses <code>source</code> for a number. This method can parse normal, + * numeric values as well as special values. These special values include + * Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY. + * + * @param source the string to parse + * @param format the number format used to parse normal, numeric values. + * @param pos input/ouput parsing parameter. + * @return the parsed number. + */ + protected Number parseNumber(final String source, final NumberFormat format, + final ParsePosition pos) { + final int startIndex = pos.getIndex(); + Number number = format.parse(source, pos); + final int endIndex = pos.getIndex(); + + // check for error parsing number + if (startIndex == endIndex) { + // try parsing special numbers + final double[] special = { + Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY + }; + for (int i = 0; i < special.length; ++i) { + number = parseNumber(source, special[i], pos); + if (number != null) { + break; + } + } + } + + return number; + } + + /** + * Parse <code>source</code> for an expected fixed string. + * @param source the string to parse + * @param expected expected string + * @param pos input/ouput parsing parameter. + * @return true if the expected string was there + */ + protected boolean parseFixedstring(final String source, final String expected, + final ParsePosition pos) { + + final int startIndex = pos.getIndex(); + final int endIndex = startIndex + expected.length(); + if ((startIndex >= source.length()) || + (endIndex > source.length()) || + (source.substring(startIndex, endIndex).compareTo(expected) != 0)) { + // set index back to start, error index should be the start index + pos.setIndex(startIndex); + pos.setErrorIndex(startIndex); + return false; + } + + // the string was here + pos.setIndex(endIndex); + return true; + + } + + /** + * Formats a double value to produce a string. In general, the value is + * formatted using the formatting rules of <code>format</code>. There are + * three exceptions to this: + * <ol> + * <li>NaN is formatted as '(NaN)'</li> + * <li>Positive infinity is formatted as '(Infinity)'</li> + * <li>Negative infinity is formatted as '(-Infinity)'</li> + * </ol> + * + * @param value the double to format. + * @param format the format used. + * @param toAppendTo where the text is to be appended + * @param pos On input: an alignment field, if desired. On output: the + * offsets of the alignment field + * @return the value passed in as toAppendTo. + */ + protected StringBuffer formatDouble(final double value, final NumberFormat format, + final StringBuffer toAppendTo, + final FieldPosition pos) { + if( Double.isNaN(value) || Double.isInfinite(value) ) { + toAppendTo.append('('); + toAppendTo.append(value); + toAppendTo.append(')'); + } else { + format.format(value, toAppendTo, pos); + } + return toAppendTo; + } + +} |