001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.math3.linear; 019 020 import java.text.FieldPosition; 021 import java.text.NumberFormat; 022 import java.text.ParsePosition; 023 import java.util.ArrayList; 024 import java.util.List; 025 import java.util.Locale; 026 027 import org.apache.commons.math3.exception.MathParseException; 028 import org.apache.commons.math3.util.CompositeFormat; 029 030 /** 031 * Formats a vector in components list format "{v0; v1; ...; vk-1}". 032 * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by 033 * any user-defined strings. The number format for components can be configured.</p> 034 * <p>White space is ignored at parse time, even if it is in the prefix, suffix 035 * or separator specifications. So even if the default separator does include a space 036 * character that is used at format time, both input string "{1;1;1}" and 037 * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be 038 * returned. In the second case, however, the parse position after parsing will be 039 * just after the closing curly brace, i.e. just before the trailing space.</p> 040 * 041 * @version $Id: RealVectorFormat.java 1416643 2012-12-03 19:37:14Z tn $ 042 * @since 2.0 043 */ 044 public class RealVectorFormat { 045 046 /** The default prefix: "{". */ 047 private static final String DEFAULT_PREFIX = "{"; 048 /** The default suffix: "}". */ 049 private static final String DEFAULT_SUFFIX = "}"; 050 /** The default separator: ", ". */ 051 private static final String DEFAULT_SEPARATOR = "; "; 052 /** Prefix. */ 053 private final String prefix; 054 /** Suffix. */ 055 private final String suffix; 056 /** Separator. */ 057 private final String separator; 058 /** Trimmed prefix. */ 059 private final String trimmedPrefix; 060 /** Trimmed suffix. */ 061 private final String trimmedSuffix; 062 /** Trimmed separator. */ 063 private final String trimmedSeparator; 064 /** The format used for components. */ 065 private final NumberFormat format; 066 067 /** 068 * Create an instance with default settings. 069 * <p>The instance uses the default prefix, suffix and separator: 070 * "{", "}", and "; " and the default number format for components.</p> 071 */ 072 public RealVectorFormat() { 073 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, 074 CompositeFormat.getDefaultNumberFormat()); 075 } 076 077 /** 078 * Create an instance with a custom number format for components. 079 * @param format the custom format for components. 080 */ 081 public RealVectorFormat(final NumberFormat format) { 082 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format); 083 } 084 085 /** 086 * Create an instance with custom prefix, suffix and separator. 087 * @param prefix prefix to use instead of the default "{" 088 * @param suffix suffix to use instead of the default "}" 089 * @param separator separator to use instead of the default "; " 090 */ 091 public RealVectorFormat(final String prefix, final String suffix, 092 final String separator) { 093 this(prefix, suffix, separator, 094 CompositeFormat.getDefaultNumberFormat()); 095 } 096 097 /** 098 * Create an instance with custom prefix, suffix, separator and format 099 * for components. 100 * @param prefix prefix to use instead of the default "{" 101 * @param suffix suffix to use instead of the default "}" 102 * @param separator separator to use instead of the default "; " 103 * @param format the custom format for components. 104 */ 105 public RealVectorFormat(final String prefix, final String suffix, 106 final String separator, final NumberFormat format) { 107 this.prefix = prefix; 108 this.suffix = suffix; 109 this.separator = separator; 110 trimmedPrefix = prefix.trim(); 111 trimmedSuffix = suffix.trim(); 112 trimmedSeparator = separator.trim(); 113 this.format = format; 114 } 115 116 /** 117 * Get the set of locales for which real vectors formats are available. 118 * <p>This is the same set as the {@link NumberFormat} set.</p> 119 * @return available real vector format locales. 120 */ 121 public static Locale[] getAvailableLocales() { 122 return NumberFormat.getAvailableLocales(); 123 } 124 125 /** 126 * Get the format prefix. 127 * @return format prefix. 128 */ 129 public String getPrefix() { 130 return prefix; 131 } 132 133 /** 134 * Get the format suffix. 135 * @return format suffix. 136 */ 137 public String getSuffix() { 138 return suffix; 139 } 140 141 /** 142 * Get the format separator between components. 143 * @return format separator. 144 */ 145 public String getSeparator() { 146 return separator; 147 } 148 149 /** 150 * Get the components format. 151 * @return components format. 152 */ 153 public NumberFormat getFormat() { 154 return format; 155 } 156 157 /** 158 * Returns the default real vector format for the current locale. 159 * @return the default real vector format. 160 */ 161 public static RealVectorFormat getInstance() { 162 return getInstance(Locale.getDefault()); 163 } 164 165 /** 166 * Returns the default real vector format for the given locale. 167 * @param locale the specific locale used by the format. 168 * @return the real vector format specific to the given locale. 169 */ 170 public static RealVectorFormat getInstance(final Locale locale) { 171 return new RealVectorFormat(CompositeFormat.getDefaultNumberFormat(locale)); 172 } 173 174 /** 175 * This method calls {@link #format(RealVector,StringBuffer,FieldPosition)}. 176 * 177 * @param v RealVector object to format. 178 * @return a formatted vector. 179 */ 180 public String format(RealVector v) { 181 return format(v, new StringBuffer(), new FieldPosition(0)).toString(); 182 } 183 184 /** 185 * Formats a {@link RealVector} object to produce a string. 186 * @param vector the object to format. 187 * @param toAppendTo where the text is to be appended 188 * @param pos On input: an alignment field, if desired. On output: the 189 * offsets of the alignment field 190 * @return the value passed in as toAppendTo. 191 */ 192 public StringBuffer format(RealVector vector, StringBuffer toAppendTo, 193 FieldPosition pos) { 194 195 pos.setBeginIndex(0); 196 pos.setEndIndex(0); 197 198 // format prefix 199 toAppendTo.append(prefix); 200 201 // format components 202 for (int i = 0; i < vector.getDimension(); ++i) { 203 if (i > 0) { 204 toAppendTo.append(separator); 205 } 206 CompositeFormat.formatDouble(vector.getEntry(i), format, toAppendTo, pos); 207 } 208 209 // format suffix 210 toAppendTo.append(suffix); 211 212 return toAppendTo; 213 } 214 215 /** 216 * Parse a string to produce a {@link RealVector} object. 217 * 218 * @param source String to parse. 219 * @return the parsed {@link RealVector} object. 220 * @throws MathParseException if the beginning of the specified string 221 * cannot be parsed. 222 */ 223 public ArrayRealVector parse(String source) { 224 final ParsePosition parsePosition = new ParsePosition(0); 225 final ArrayRealVector result = parse(source, parsePosition); 226 if (parsePosition.getIndex() == 0) { 227 throw new MathParseException(source, 228 parsePosition.getErrorIndex(), 229 ArrayRealVector.class); 230 } 231 return result; 232 } 233 234 /** 235 * Parse a string to produce a {@link RealVector} object. 236 * 237 * @param source String to parse. 238 * @param pos input/ouput parsing parameter. 239 * @return the parsed {@link RealVector} object. 240 */ 241 public ArrayRealVector parse(String source, ParsePosition pos) { 242 int initialIndex = pos.getIndex(); 243 244 // parse prefix 245 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 246 if (!CompositeFormat.parseFixedstring(source, trimmedPrefix, pos)) { 247 return null; 248 } 249 250 // parse components 251 List<Number> components = new ArrayList<Number>(); 252 for (boolean loop = true; loop;){ 253 254 if (!components.isEmpty()) { 255 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 256 if (!CompositeFormat.parseFixedstring(source, trimmedSeparator, pos)) { 257 loop = false; 258 } 259 } 260 261 if (loop) { 262 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 263 Number component = CompositeFormat.parseNumber(source, format, pos); 264 if (component != null) { 265 components.add(component); 266 } else { 267 // invalid component 268 // set index back to initial, error index should already be set 269 pos.setIndex(initialIndex); 270 return null; 271 } 272 } 273 274 } 275 276 // parse suffix 277 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 278 if (!CompositeFormat.parseFixedstring(source, trimmedSuffix, pos)) { 279 return null; 280 } 281 282 // build vector 283 double[] data = new double[components.size()]; 284 for (int i = 0; i < data.length; ++i) { 285 data[i] = components.get(i).doubleValue(); 286 } 287 return new ArrayRealVector(data, false); 288 } 289 }