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 18 package org.apache.commons.math.linear; 19 20 import java.text.FieldPosition; 21 import java.text.NumberFormat; 22 import java.text.ParseException; 23 import java.text.ParsePosition; 24 import java.util.ArrayList; 25 import java.util.List; 26 import java.util.Locale; 27 28 import org.apache.commons.math.MathRuntimeException; 29 import org.apache.commons.math.util.CompositeFormat; 30 31 /** 32 * Formats a vector in components list format "{v0; v1; ...; vk-1}". 33 * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by 34 * any user-defined strings. The number format for components can be configured.</p> 35 * <p>White space is ignored at parse time, even if it is in the prefix, suffix 36 * or separator specifications. So even if the default separator does include a space 37 * character that is used at format time, both input string "{1;1;1}" and 38 * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be 39 * returned. In the second case, however, the parse position after parsing will be 40 * just after the closing curly brace, i.e. just before the trailing space.</p> 41 * 42 * @version $Revision: 783702 $ $Date: 2009-06-11 04:54:02 -0400 (Thu, 11 Jun 2009) $ 43 * @since 2.0 44 */ 45 public class RealVectorFormat extends CompositeFormat { 46 47 /** Serializable version identifier */ 48 private static final long serialVersionUID = -708767813036157690L; 49 50 /** The default prefix: "{". */ 51 private static final String DEFAULT_PREFIX = "{"; 52 53 /** The default suffix: "}". */ 54 private static final String DEFAULT_SUFFIX = "}"; 55 56 /** The default separator: ", ". */ 57 private static final String DEFAULT_SEPARATOR = "; "; 58 59 /** Prefix. */ 60 private final String prefix; 61 62 /** Suffix. */ 63 private final String suffix; 64 65 /** Separator. */ 66 private final String separator; 67 68 /** Trimmed prefix. */ 69 private final String trimmedPrefix; 70 71 /** Trimmed suffix. */ 72 private final String trimmedSuffix; 73 74 /** Trimmed separator. */ 75 private final String trimmedSeparator; 76 77 /** The format used for components. */ 78 private NumberFormat format; 79 80 /** 81 * Create an instance with default settings. 82 * <p>The instance uses the default prefix, suffix and separator: 83 * "{", "}", and "; " and the default number format for components.</p> 84 */ 85 public RealVectorFormat() { 86 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, getDefaultNumberFormat()); 87 } 88 89 /** 90 * Create an instance with a custom number format for components. 91 * @param format the custom format for components. 92 */ 93 public RealVectorFormat(final NumberFormat format) { 94 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format); 95 } 96 97 /** 98 * Create an instance with custom prefix, suffix and separator. 99 * @param prefix prefix to use instead of the default "{" 100 * @param suffix suffix to use instead of the default "}" 101 * @param separator separator to use instead of the default "; " 102 */ 103 public RealVectorFormat(final String prefix, final String suffix, 104 final String separator) { 105 this(prefix, suffix, separator, getDefaultNumberFormat()); 106 } 107 108 /** 109 * Create an instance with custom prefix, suffix, separator and format 110 * for components. 111 * @param prefix prefix to use instead of the default "{" 112 * @param suffix suffix to use instead of the default "}" 113 * @param separator separator to use instead of the default "; " 114 * @param format the custom format for components. 115 */ 116 public RealVectorFormat(final String prefix, final String suffix, 117 final String separator, final NumberFormat format) { 118 this.prefix = prefix; 119 this.suffix = suffix; 120 this.separator = separator; 121 trimmedPrefix = prefix.trim(); 122 trimmedSuffix = suffix.trim(); 123 trimmedSeparator = separator.trim(); 124 this.format = format; 125 } 126 127 /** 128 * Get the set of locales for which real vectors formats are available. 129 * <p>This is the same set as the {@link NumberFormat} set.</p> 130 * @return available real vector format locales. 131 */ 132 public static Locale[] getAvailableLocales() { 133 return NumberFormat.getAvailableLocales(); 134 } 135 136 /** 137 * Get the format prefix. 138 * @return format prefix. 139 */ 140 public String getPrefix() { 141 return prefix; 142 } 143 144 /** 145 * Get the format suffix. 146 * @return format suffix. 147 */ 148 public String getSuffix() { 149 return suffix; 150 } 151 152 /** 153 * Get the format separator between components. 154 * @return format separator. 155 */ 156 public String getSeparator() { 157 return separator; 158 } 159 160 /** 161 * Get the components format. 162 * @return components format. 163 */ 164 public NumberFormat getFormat() { 165 return format; 166 } 167 168 /** 169 * Returns the default real vector format for the current locale. 170 * @return the default real vector format. 171 */ 172 public static RealVectorFormat getInstance() { 173 return getInstance(Locale.getDefault()); 174 } 175 176 /** 177 * Returns the default real vector format for the given locale. 178 * @param locale the specific locale used by the format. 179 * @return the real vector format specific to the given locale. 180 */ 181 public static RealVectorFormat getInstance(final Locale locale) { 182 return new RealVectorFormat(getDefaultNumberFormat(locale)); 183 } 184 185 /** 186 * This static method calls {@link #format(Object)} on a default instance of 187 * RealVectorFormat. 188 * 189 * @param v RealVector object to format 190 * @return A formatted vector 191 */ 192 public static String formatRealVector(RealVector v) { 193 return getInstance().format(v); 194 } 195 196 /** 197 * Formats a {@link RealVector} object to produce a string. 198 * @param vector the object to format. 199 * @param toAppendTo where the text is to be appended 200 * @param pos On input: an alignment field, if desired. On output: the 201 * offsets of the alignment field 202 * @return the value passed in as toAppendTo. 203 */ 204 public StringBuffer format(RealVector vector, StringBuffer toAppendTo, 205 FieldPosition pos) { 206 207 pos.setBeginIndex(0); 208 pos.setEndIndex(0); 209 210 // format prefix 211 toAppendTo.append(prefix); 212 213 // format components 214 for (int i = 0; i < vector.getDimension(); ++i) { 215 if (i > 0) { 216 toAppendTo.append(separator); 217 } 218 formatDouble(vector.getEntry(i), format, toAppendTo, pos); 219 } 220 221 // format suffix 222 toAppendTo.append(suffix); 223 224 return toAppendTo; 225 226 } 227 228 /** 229 * Formats a object to produce a string. 230 * <p><code>obj</code> must be a {@link RealVector} object. Any other type of 231 * object will result in an {@link IllegalArgumentException} being thrown.</p> 232 * @param obj the object to format. 233 * @param toAppendTo where the text is to be appended 234 * @param pos On input: an alignment field, if desired. On output: the 235 * offsets of the alignment field 236 * @return the value passed in as toAppendTo. 237 * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition) 238 * @throws IllegalArgumentException is <code>obj</code> is not a valid type. 239 */ 240 @Override 241 public StringBuffer format(Object obj, StringBuffer toAppendTo, 242 FieldPosition pos) { 243 244 if (obj instanceof RealVector) { 245 return format( (RealVector)obj, toAppendTo, pos); 246 } 247 248 throw MathRuntimeException.createIllegalArgumentException( 249 "cannot format a {0} instance as a real vector", 250 obj.getClass().getName()); 251 252 } 253 254 /** 255 * Parses a string to produce a {@link RealVector} object. 256 * @param source the string to parse 257 * @return the parsed {@link RealVector} object. 258 * @exception ParseException if the beginning of the specified string 259 * cannot be parsed. 260 */ 261 public ArrayRealVector parse(String source) throws ParseException { 262 ParsePosition parsePosition = new ParsePosition(0); 263 ArrayRealVector result = parse(source, parsePosition); 264 if (parsePosition.getIndex() == 0) { 265 throw MathRuntimeException.createParseException( 266 parsePosition.getErrorIndex(), 267 "unparseable real vector: \"{0}\"", source); 268 } 269 return result; 270 } 271 272 /** 273 * Parses a string to produce a {@link RealVector} object. 274 * @param source the string to parse 275 * @param pos input/ouput parsing parameter. 276 * @return the parsed {@link RealVector} object. 277 */ 278 public ArrayRealVector parse(String source, ParsePosition pos) { 279 int initialIndex = pos.getIndex(); 280 281 // parse prefix 282 parseAndIgnoreWhitespace(source, pos); 283 if (!parseFixedstring(source, trimmedPrefix, pos)) { 284 return null; 285 } 286 287 // parse components 288 List<Number> components = new ArrayList<Number>(); 289 for (boolean loop = true; loop;){ 290 291 if (!components.isEmpty()) { 292 parseAndIgnoreWhitespace(source, pos); 293 if (!parseFixedstring(source, trimmedSeparator, pos)) { 294 loop = false; 295 } 296 } 297 298 if (loop) { 299 parseAndIgnoreWhitespace(source, pos); 300 Number component = parseNumber(source, format, pos); 301 if (component != null) { 302 components.add(component); 303 } else { 304 // invalid component 305 // set index back to initial, error index should already be set 306 pos.setIndex(initialIndex); 307 return null; 308 } 309 } 310 311 } 312 313 // parse suffix 314 parseAndIgnoreWhitespace(source, pos); 315 if (!parseFixedstring(source, trimmedSuffix, pos)) { 316 return null; 317 } 318 319 // build vector 320 double[] data = new double[components.size()]; 321 for (int i = 0; i < data.length; ++i) { 322 data[i] = components.get(i).doubleValue(); 323 } 324 return new ArrayRealVector(data, false); 325 326 } 327 328 /** 329 * Parses a string to produce a object. 330 * @param source the string to parse 331 * @param pos input/ouput parsing parameter. 332 * @return the parsed object. 333 * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) 334 */ 335 @Override 336 public Object parseObject(String source, ParsePosition pos) { 337 return parse(source, pos); 338 } 339 340 }