📄 messageformat.java
字号:
* When the result is parsed, it will return {"a", "b,c"}. * <li>If a single argument is parsed more than once in the string, * then the later parse wins. * </ul> * When the parse fails, use ParsePosition.getErrorIndex() to find out * where in the string did the parsing failed. The returned error * index is the starting offset of the sub-patterns that the string * is comparing with. For example, if the parsing string "AAA {0} BBB" * is comparing against the pattern "AAD {0} BBB", the error index is * 0. When an error occurs, the call to this method will return null. * If the source is null, return an empty array. */ public Object[] parse(String source, ParsePosition pos) { if (source == null) { Object[] empty = {}; return empty; } int maximumArgumentNumber = -1; for (int i = 0; i <= maxOffset; i++) { if (argumentNumbers[i] > maximumArgumentNumber) { maximumArgumentNumber = argumentNumbers[i]; } } Object[] resultArray = new Object[maximumArgumentNumber + 1]; int patternOffset = 0; int sourceOffset = pos.index; ParsePosition tempStatus = new ParsePosition(0); for (int i = 0; i <= maxOffset; ++i) { // match up to format int len = offsets[i] - patternOffset; if (len == 0 || pattern.regionMatches(patternOffset, source, sourceOffset, len)) { sourceOffset += len; patternOffset += len; } else { pos.errorIndex = sourceOffset; return null; // leave index as is to signal error } // now use format if (formats[i] == null) { // string format // if at end, use longest possible match // otherwise uses first match to intervening string // does NOT recursively try all possibilities int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length(); int next; if (patternOffset >= tempLength) { next = source.length(); }else{ next = source.indexOf( pattern.substring(patternOffset,tempLength), sourceOffset); } if (next < 0) { pos.errorIndex = sourceOffset; return null; // leave index as is to signal error } else { String strValue= source.substring(sourceOffset,next); if (!strValue.equals("{"+argumentNumbers[i]+"}")) resultArray[argumentNumbers[i]] = source.substring(sourceOffset,next); sourceOffset = next; } } else { tempStatus.index = sourceOffset; resultArray[argumentNumbers[i]] = formats[i].parseObject(source,tempStatus); if (tempStatus.index == sourceOffset) { pos.errorIndex = sourceOffset; return null; // leave index as is to signal error } sourceOffset = tempStatus.index; // update } } int len = pattern.length() - patternOffset; if (len == 0 || pattern.regionMatches(patternOffset, source, sourceOffset, len)) { pos.index = sourceOffset + len; } else { pos.errorIndex = sourceOffset; return null; // leave index as is to signal error } return resultArray; } /** * Parses text from the beginning of the given string to produce an object * array. * The method may not use the entire text of the given string. * <p> * See the {@link #parse(String, ParsePosition)} method for more information * on message parsing. * * @param source A <code>String</code> whose beginning should be parsed. * @return An <code>Object</code> array parsed from the string. * @exception ParseException if the beginning of the specified string * cannot be parsed. */ public Object[] parse(String source) throws ParseException { ParsePosition pos = new ParsePosition(0); Object[] result = parse(source, pos); if (pos.index == 0) // unchanged, returned object is null throw new ParseException("MessageFormat parse error!", pos.errorIndex); return result; } /** * Parses text from a string to produce an object array. * <p> * The method attempts to parse text starting at the index given by * <code>pos</code>. * If parsing succeeds, then the index of <code>pos</code> is updated * to the index after the last character used (parsing does not necessarily * use all characters up to the end of the string), and the parsed * object array is returned. The updated <code>pos</code> can be used to * indicate the starting point for the next call to this method. * If an error occurs, then the index of <code>pos</code> is not * changed, the error index of <code>pos</code> is set to the index of * the character where the error occurred, and null is returned. * <p> * See the {@link #parse(String, ParsePosition)} method for more information * on message parsing. * * @param source A <code>String</code>, part of which should be parsed. * @param pos A <code>ParsePosition</code> object with index and error * index information as described above. * @return An <code>Object</code> array parsed from the string. In case of * error, returns null. * @exception NullPointerException if <code>pos</code> is null. */ public Object parseObject(String source, ParsePosition pos) { return parse(source, pos); } /** * Creates and returns a copy of this object. * * @return a clone of this instance. */ public Object clone() { MessageFormat other = (MessageFormat) super.clone(); // clone arrays. Can't do with utility because of bug in Cloneable other.formats = (Format[]) formats.clone(); // shallow clone for (int i = 0; i < formats.length; ++i) { if (formats[i] != null) other.formats[i] = (Format)formats[i].clone(); } // for primitives or immutables, shallow clone is enough other.offsets = (int[]) offsets.clone(); other.argumentNumbers = (int[]) argumentNumbers.clone(); return other; } /** * Equality comparison between two message format objects */ public boolean equals(Object obj) { if (this == obj) // quick check return true; if (obj == null || getClass() != obj.getClass()) return false; MessageFormat other = (MessageFormat) obj; return (maxOffset == other.maxOffset && pattern.equals(other.pattern) && Utility.objectEquals(locale, other.locale) // does null check && Utility.arrayEquals(offsets,other.offsets) && Utility.arrayEquals(argumentNumbers,other.argumentNumbers) && Utility.arrayEquals(formats,other.formats)); } /** * Generates a hash code for the message format object. */ public int hashCode() { return pattern.hashCode(); // enough for reasonable distribution } /** * Defines constants that are used as attribute keys in the * <code>AttributedCharacterIterator</code> returned * from <code>MessageFormat.formatToCharacterIterator</code>. * * @since 1.4 */ public static class Field extends Format.Field { /** * Creates a Field with the specified name. * * @param name Name of the attribute */ protected Field(String name) { super(name); } /** * Resolves instances being deserialized to the predefined constants. * * @throws InvalidObjectException if the constant could not be * resolved. * @return resolved MessageFormat.Field constant */ protected Object readResolve() throws InvalidObjectException { if (this.getClass() != MessageFormat.Field.class) { throw new InvalidObjectException("subclass didn't correctly implement readResolve"); } return ARGUMENT; } // // The constants // /** * Constant identifying a portion of a message that was generated * from an argument passed into <code>formatToCharacterIterator</code>. * The value associated with the key will be an <code>Integer</code> * indicating the index in the <code>arguments</code> array of the * argument from which the text was generated. */ public final static Field ARGUMENT = new Field("message argument field"); } // ===========================privates============================ /** * The locale to use for formatting numbers and dates. * @serial */ private Locale locale; /** * The string that the formatted values are to be plugged into. In other words, this * is the pattern supplied on construction with all of the {} expressions taken out. * @serial */ private String pattern = ""; /** The initially expected number of subformats in the format */ private static final int INITIAL_FORMATS = 10; /** * An array of formatters, which are used to format the arguments. * @serial */ private Format[] formats = new Format[INITIAL_FORMATS]; /** * The positions where the results of formatting each argument are to be inserted * into the pattern. * @serial */ private int[] offsets = new int[INITIAL_FORMATS]; /** * The argument numbers corresponding to each formatter. (The formatters are stored * in the order they occur in the pattern, not in the order in which the arguments * are specified.) * @serial */ private int[] argumentNumbers = new int[INITIAL_FORMATS]; /** * One less than the number of entries in <code>offsets</code>. Can also be thought of * as the index of the highest-numbered element in <code>offsets</code> that is being used. * All of these arrays should have the same number of elements being used as <code>offsets</code> * does, and so this variable suffices to tell us how many entries are in all of them. * @serial */ private int maxOffset = -1; /** * Internal routine used by format. If <code>characterIterators</code> is * non-null, AttributedCharacterIterator will be created from the * subformats as necessary. If <code>characterIterators</code> is null * and <code>fp</code> is non-null and identifies * <code>Field.MESSAGE_ARGUMENT</code>, the location of * the first replaced argument will be set in it. * * @exception IllegalArgumentException if an argument in the * <code>arguments</code> array is not of the type * expected by the format element(s) that use it. */ private StringBuffer subformat(Object[] arguments, StringBuffer result, FieldPosition fp, List characterIterators) { // note: this implementation assumes a fast substring & index. // if this is not true, would be better to append chars one by one. int lastOffset = 0; int last = result.length(); for (int i = 0; i <= maxOffset; ++i) { result.append(pattern.substring(lastOffset, offsets[i]));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -