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 java.text; 19 20 import java.io.Serializable; 21 22 /** 23 * The base class for all formats. 24 * <p> 25 * This is an abstract base class which specifies the protocol for classes which 26 * convert other objects or values, such as numeric values and dates, and their 27 * string representations. In some cases these representations may be localized 28 * or contain localized characters or strings. For example, a numeric formatter 29 * such as {@code DecimalFormat} may convert a numeric value such as 12345 to 30 * the string "$12,345". It may also parse the string back into a numeric value. 31 * A date and time formatter like {@code SimpleDateFormat} may represent a 32 * specific date, encoded numerically, as a string such as "Wednesday, February 33 * 26, 1997 AD". 34 * <p> 35 * Many of the concrete subclasses of {@code Format} employ the notion of a 36 * pattern. A pattern is a string representation of the rules which govern the 37 * conversion between values and strings. For example, a {@code DecimalFormat} 38 * object may be associated with the pattern "$#,##0.00;($#,##0.00)", which is a 39 * common US English format for currency values, yielding strings such as 40 * "$1,234.45" for 1234.45, and "($987.65)" for -987.6543. The specific syntax 41 * of a pattern is defined by each subclass. Even though many subclasses use 42 * patterns, the notion of a pattern is not inherent to {@code Format} classes 43 * in general, and is not part of the explicit base class protocol. 44 * <p> 45 * Two complex formatting classes are worth mentioning: {@code MessageFormat} 46 * and {@code ChoiceFormat}. {@code ChoiceFormat} is a subclass of 47 * {@code NumberFormat} which allows the user to format different number ranges 48 * as strings. For instance, 0 may be represented as "no files", 1 as "one 49 * file", and any number greater than 1 as "many files". {@code MessageFormat} 50 * is a formatter which utilizes other {@code Format} objects to format a string 51 * containing multiple values. For instance, a {@code MessageFormat} object 52 * might produce the string "There are no files on the disk MyDisk on February 53 * 27, 1997." given the arguments 0, "MyDisk", and the date value of 2/27/97. 54 * See the {@link ChoiceFormat} and {@link MessageFormat} descriptions for 55 * further information. 56 */ 57 public abstract class Format implements Serializable, Cloneable { 58 59 private static final long serialVersionUID = -299282585814624189L; 60 61 /** 62 * Used by subclasses. This was public in Java 5. 63 */ Format()64 protected Format() { 65 } 66 67 /** 68 * Returns a copy of this {@code Format} instance. 69 * 70 * @return a shallow copy of this format. 71 * 72 * @see java.lang.Cloneable 73 */ 74 @Override clone()75 public Object clone() { 76 try { 77 return super.clone(); 78 } catch (CloneNotSupportedException e) { 79 throw new AssertionError(e); 80 } 81 } 82 83 /** 84 * Formats the specified object using the rules of this format. 85 * 86 * @param object 87 * the object to format. 88 * @return the formatted string. 89 * @throws IllegalArgumentException 90 * if the object cannot be formatted by this format. 91 */ format(Object object)92 public final String format(Object object) { 93 return format(object, new StringBuffer(), new FieldPosition(0)) 94 .toString(); 95 } 96 97 /** 98 * Appends the specified object to the specified string buffer using the 99 * rules of this format. 100 * <p> 101 * {@code field} is an input/output parameter. If its {@code field} 102 * member contains an enum value specifying a field on input, then its 103 * {@code beginIndex} and {@code endIndex} members will be updated with the 104 * text offset of the first occurrence of this field in the formatted text. 105 * 106 * @param object 107 * the object to format. 108 * @param buffer 109 * the string buffer where the formatted string is appended to. 110 * @param field 111 * on input: an optional alignment field; on output: the offsets 112 * of the alignment field in the formatted text. 113 * @return the string buffer. 114 * @throws IllegalArgumentException 115 * if the object cannot be formatted by this format. 116 */ format(Object object, StringBuffer buffer, FieldPosition field)117 public abstract StringBuffer format(Object object, StringBuffer buffer, 118 FieldPosition field); 119 120 /** 121 * Formats the specified object using the rules of this format and returns 122 * an {@code AttributedCharacterIterator} with the formatted string and no 123 * attributes. 124 * <p> 125 * Subclasses should return an {@code AttributedCharacterIterator} with the 126 * appropriate attributes. 127 * 128 * @param object 129 * the object to format. 130 * @return an {@code AttributedCharacterIterator} with the formatted object 131 * and attributes. 132 * @throws IllegalArgumentException 133 * if the object cannot be formatted by this format. 134 */ formatToCharacterIterator(Object object)135 public AttributedCharacterIterator formatToCharacterIterator(Object object) { 136 return new AttributedString(format(object)).getIterator(); 137 } 138 139 /** 140 * Parses the specified string using the rules of this format. 141 * 142 * @param string 143 * the string to parse. 144 * @return the object resulting from the parse. 145 * @throws ParseException 146 * if an error occurs during parsing. 147 */ parseObject(String string)148 public Object parseObject(String string) throws ParseException { 149 ParsePosition position = new ParsePosition(0); 150 Object result = parseObject(string, position); 151 if (position.getIndex() == 0) { 152 throw new ParseException("Parse failure", position.getErrorIndex()); 153 } 154 return result; 155 } 156 157 /** 158 * Parses the specified string starting at the index specified by 159 * {@code position}. If the string is successfully parsed then the index of 160 * the {@code ParsePosition} is updated to the index following the parsed 161 * text. On error, the index is unchanged and the error index of 162 * {@code ParsePosition} is set to the index where the error occurred. 163 * 164 * @param string 165 * the string to parse. 166 * @param position 167 * input/output parameter, specifies the start index in 168 * {@code string} from where to start parsing. If parsing is 169 * successful, it is updated with the index following the parsed 170 * text; on error, the index is unchanged and the error index is 171 * set to the index where the error occurred. 172 * @return the object resulting from the parse or {@code null} if there is 173 * an error. 174 */ parseObject(String string, ParsePosition position)175 public abstract Object parseObject(String string, ParsePosition position); 176 upTo(String string, ParsePosition position, StringBuffer buffer, char stop)177 static boolean upTo(String string, ParsePosition position, 178 StringBuffer buffer, char stop) { 179 int index = position.getIndex(), length = string.length(); 180 boolean lastQuote = false, quote = false; 181 while (index < length) { 182 char ch = string.charAt(index++); 183 if (ch == '\'') { 184 if (lastQuote) { 185 buffer.append('\''); 186 } 187 quote = !quote; 188 lastQuote = true; 189 } else if (ch == stop && !quote) { 190 position.setIndex(index); 191 return true; 192 } else { 193 lastQuote = false; 194 buffer.append(ch); 195 } 196 } 197 position.setIndex(index); 198 return false; 199 } 200 upToWithQuotes(String string, ParsePosition position, StringBuffer buffer, char stop, char start)201 static boolean upToWithQuotes(String string, ParsePosition position, 202 StringBuffer buffer, char stop, char start) { 203 int index = position.getIndex(), length = string.length(), count = 1; 204 boolean quote = false; 205 while (index < length) { 206 char ch = string.charAt(index++); 207 if (ch == '\'') { 208 quote = !quote; 209 } 210 if (!quote) { 211 if (ch == stop) { 212 count--; 213 } 214 if (count == 0) { 215 position.setIndex(index); 216 return true; 217 } 218 if (ch == start) { 219 count++; 220 } 221 } 222 buffer.append(ch); 223 } 224 throw new IllegalArgumentException("Unmatched braces in the pattern"); 225 } 226 227 /** 228 * Inner class used to represent {@code Format} attributes in the 229 * {@code AttributedCharacterIterator} that the 230 * {@code formatToCharacterIterator()} method returns in {@code Format} 231 * subclasses. 232 */ 233 public static class Field extends AttributedCharacterIterator.Attribute { 234 235 private static final long serialVersionUID = 276966692217360283L; 236 237 /** 238 * Constructs a new instance of {@code Field} with the given field name. 239 * 240 * @param fieldName 241 * the field name. 242 */ Field(String fieldName)243 protected Field(String fieldName) { 244 super(fieldName); 245 } 246 } 247 } 248