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 package org.hipparchus.util; 23 24 import java.text.FieldPosition; 25 import java.text.NumberFormat; 26 import java.text.ParsePosition; 27 import java.util.Locale; 28 29 /** 30 * Base class for formatters of composite objects (complex numbers, vectors ...). 31 */ 32 public class CompositeFormat { 33 34 /** 35 * Class contains only static methods. 36 */ 37 private CompositeFormat() {} 38 39 /** 40 * Create a default number format. The default number format is based on 41 * {@link NumberFormat#getInstance()} with the only customizing that the 42 * maximum number of fraction digits is set to 10. 43 * @return the default number format. 44 */ 45 public static NumberFormat getDefaultNumberFormat() { 46 return getDefaultNumberFormat(Locale.getDefault()); 47 } 48 49 /** 50 * Create a default number format. The default number format is based on 51 * {@link NumberFormat#getInstance(java.util.Locale)} with the only 52 * customizing that the maximum number of fraction digits is set to 10. 53 * @param locale the specific locale used by the format. 54 * @return the default number format specific to the given locale. 55 */ 56 public static NumberFormat getDefaultNumberFormat(final Locale locale) { 57 final NumberFormat nf = NumberFormat.getInstance(locale); 58 nf.setMaximumFractionDigits(10); 59 return nf; 60 } 61 62 /** 63 * Parses <code>source</code> until a non-whitespace character is found. 64 * 65 * @param source the string to parse 66 * @param pos input/output parsing parameter. On output, <code>pos</code> 67 * holds the index of the next non-whitespace character. 68 */ 69 public static void parseAndIgnoreWhitespace(final String source, 70 final ParsePosition pos) { 71 parseNextCharacter(source, pos); 72 pos.setIndex(pos.getIndex() - 1); 73 } 74 75 /** 76 * Parses <code>source</code> until a non-whitespace character is found. 77 * 78 * @param source the string to parse 79 * @param pos input/output parsing parameter. 80 * @return the first non-whitespace character. 81 */ 82 public static char parseNextCharacter(final String source, 83 final ParsePosition pos) { 84 int index = pos.getIndex(); 85 final int n = source.length(); 86 char ret = 0; 87 88 if (index < n) { 89 char c; 90 do { 91 c = source.charAt(index++); 92 } while (Character.isWhitespace(c) && index < n); 93 pos.setIndex(index); 94 95 if (index < n) { 96 ret = c; 97 } 98 } 99 100 return ret; 101 } 102 103 /** 104 * Parses <code>source</code> for special double values. These values 105 * include Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY. 106 * 107 * @param source the string to parse 108 * @param value the special value to parse. 109 * @param pos input/output parsing parameter. 110 * @return the special number. 111 */ 112 private static Number parseNumber(final String source, final double value, 113 final ParsePosition pos) { 114 Number ret = null; 115 116 StringBuilder sb = new StringBuilder(); 117 sb.append('(').append(value).append(')'); 118 119 final int n = sb.length(); 120 final int startIndex = pos.getIndex(); 121 final int endIndex = startIndex + n; 122 if (endIndex < source.length() && 123 source.substring(startIndex, endIndex).compareTo(sb.toString()) == 0) { 124 ret = Double.valueOf(value); 125 pos.setIndex(endIndex); 126 } 127 128 return ret; 129 } 130 131 /** 132 * Parses <code>source</code> for a number. This method can parse normal, 133 * numeric values as well as special values. These special values include 134 * Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY. 135 * 136 * @param source the string to parse 137 * @param format the number format used to parse normal, numeric values. 138 * @param pos input/output parsing parameter. 139 * @return the parsed number. 140 */ 141 public static Number parseNumber(final String source, final NumberFormat format, 142 final ParsePosition pos) { 143 final int startIndex = pos.getIndex(); 144 Number number = format.parse(source, pos); 145 final int endIndex = pos.getIndex(); 146 147 // check for error parsing number 148 if (startIndex == endIndex) { 149 // try parsing special numbers 150 final double[] special = { 151 Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY 152 }; 153 for (int i = 0; i < special.length; ++i) { 154 number = parseNumber(source, special[i], pos); 155 if (number != null) { 156 break; 157 } 158 } 159 } 160 161 return number; 162 } 163 164 /** 165 * Parse <code>source</code> for an expected fixed string. 166 * @param source the string to parse 167 * @param expected expected string 168 * @param pos input/output parsing parameter. 169 * @return true if the expected string was there 170 */ 171 public static boolean parseFixedstring(final String source, 172 final String expected, 173 final ParsePosition pos) { 174 175 final int startIndex = pos.getIndex(); 176 final int endIndex = startIndex + expected.length(); 177 if ((startIndex >= source.length()) || 178 (endIndex > source.length()) || 179 (source.substring(startIndex, endIndex).compareTo(expected) != 0)) { 180 // set index back to start, error index should be the start index 181 pos.setIndex(startIndex); 182 pos.setErrorIndex(startIndex); 183 return false; 184 } 185 186 // the string was here 187 pos.setIndex(endIndex); 188 return true; 189 } 190 191 /** 192 * Formats a double value to produce a string. In general, the value is 193 * formatted using the formatting rules of <code>format</code>. There are 194 * three exceptions to this: 195 * <ol> 196 * <li>NaN is formatted as '(NaN)'</li> 197 * <li>Positive infinity is formatted as '(Infinity)'</li> 198 * <li>Negative infinity is formatted as '(-Infinity)'</li> 199 * </ol> 200 * 201 * @param value the double to format. 202 * @param format the format used. 203 * @param toAppendTo where the text is to be appended 204 * @param pos On input: an alignment field, if desired. On output: the 205 * offsets of the alignment field 206 * @return the value passed in as toAppendTo. 207 */ 208 public static StringBuffer formatDouble(final double value, final NumberFormat format, 209 final StringBuffer toAppendTo, 210 final FieldPosition pos) { 211 if( Double.isNaN(value) || Double.isInfinite(value) ) { 212 toAppendTo.append('('); 213 toAppendTo.append(value); 214 toAppendTo.append(')'); 215 } else { 216 format.format(value, toAppendTo, pos); 217 } 218 return toAppendTo; 219 } 220 }