messageformat.java

来自「《移动Agent技术》一书的所有章节源代码。」· Java 代码 · 共 850 行 · 第 1/3 页

JAVA
850
字号
/*
 * @(#)MessageFormat.java   1.15 97/01/29
 *
 * (C) Copyright Taligent, Inc. 1996,1997 - All Rights Reserved
 * (C) Copyright IBM Corp. 1996,1997 - All Rights Reserved
 *
 * Portions copyright (c) 1996-1997 Sun Microsystems, Inc. All Rights Reserved.
 *
 *   The original version of this source code and documentation is copyrighted
 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
 * materials are provided under terms of a License Agreement between Taligent
 * and Sun. This technology is protected by multiple US and International
 * patents. This notice and attribution to Taligent may not be removed.
 *   Taligent is a registered trademark of Taligent, Inc.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 */

package java.text;

import java.util.Date;
import java.util.Locale;
import java.text.DecimalFormat;
import java.text.Utility;
/**
 * <code>MessageFormat</code> provides a means to produce concatenated
 * messages in language-neutral way. Use this to construct messages
 * displayed for end users.
 *
 * <p>
 * <code>MessageFormat</code> takes a set of objects, formats them, then
 * inserts the formatted strings into the pattern at the appropriate places.
 *
 * <p>
 * <strong>Note:</strong>
 * <code>MessageFormat</code> differs from the other <code>Format</code>
 * classes in that you create a <code>MessageFormat</code> object with one
 * of its constructors (not with a <code>getInstance</code> style factory
 * method). The factory methods aren't necessary because <code>MessageFormat</code>
 * doesn't require any complex setup for a given locale. In fact,
 * <code>MessageFormat</code> doesn't implement any locale specific behavior
 * at all. It just needs to be set up on a sentence by sentence basis.
 *
 * <p>
 * Here are some examples of usage:
 * <blockquote>
 * <pre>
 * Object[] arguments = {
 *     new Integer(7),
 *     new Date(System.currentTimeMillis()),
 *     "a disturbance in the Force"
 * };
 *
 * String result = MessageFormat.format(
 *     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
 *     arguments);
 *
 * <output>: At 12:30 PM on Jul 3, 2053, there was a disturbance
 *           in the Force on planet 7.
 *
 * </pre>
 * </blockquote>
 * Typically, the message format will come from resources, and the
 * arguments will be dynamically set at runtime.
 *
 * <p>
 * Example 2:
 * <blockquote>
 * <pre>
 * Object[] testArgs = {new Long(3), "MyDisk"};
 *
 * MessageFormat form = new MessageFormat(
 *     "The disk \"{1}\" contains {0} file(s).");
 *
 * System.out.println(form.format(testArgs));
 *
 * // output, with different testArgs
 * <output>: The disk "MyDisk" contains 0 file(s).
 * <output>: The disk "MyDisk" contains 1 file(s).
 * <output>: The disk "MyDisk" contains 1,273 file(s).
 * </pre>
 * </blockquote>
 *
 * <p>
 * The pattern is of the form:
 * <blockquote>
 * <pre>
 * messageFormatPattern := string ( "{" messageFormatElement "}" string )*
 *
 * messageFormatElement := argument { "," elementFormat }
 *
 * elementFormat := "time" { "," datetimeStyle }
 *                | "date" { "," datetimeStyle }
 *                | "number" { "," numberStyle }
 *                | "choice" { "," choiceStyle }
 *
 * datetimeStyle := "short"
 *                  | "medium"
 *                  | "long"
 *                  | "full"
 *                  | dateFormatPattern
 *
 * numberStyle := "currency"
 *               | "percent"
 *               | "integer"
 *               | numberFormatPattern
 *
 * choiceStyle := choiceFormatPattern
 * </pre>
 * </blockquote>
 * If there is no <code>elementFormat</code>,
 * then the argument must be a string, which is substituted. If there is
 * no <code>dateTimeStyle</code> or <code>numberStyle</code>, then the
 * default format is used (for example, <code>NumberFormat.getInstance</code>,
 * <code>DateFormat.getTimeInstance</code>, or <code>DateFormat.getInstance</code>).
 *
 * <p>
 * In strings, single quotes can be used to quote the "{"
 * (curly brace) if necessary. A real single quote is represented by ''.
 * Inside a <code>messageFormatElement</code>, quotes are <strong>not</strong>
 * removed. For example, {1,number,$'#',##} will produce a number format
 * with the pound-sign quoted, with a result such as: "$#31,45".
 *
 * <p>
 * If a pattern is used, then unquoted braces in the pattern, if any, must match:
 * that is, "ab {0} de" and "ab '}' de" are ok, but "ab {0'}' de" and "ab } de" are
 * not.
 *
 * <p>
 * The argument is a number from 0 to 9, which corresponds to the
 * arguments presented in an array to be formatted.
 *
 * <p>
 * It is ok to have unused arguments in the array.
 * With missing arguments or arguments that are not of the right class for
 * the specified format, a <code>ParseException</code> is thrown.
 * First, <code>format</code> checks to see if a <code>Format</code> object has been
 * specified for the argument with the <code>setFormats</code> method.
 * If so, then <code>format</code> uses that <code>Format</code> object to format the
 * argument. Otherwise, the argument is formatted based on the object's
 * type. If the argument is a <code>Number</code>, then <code>format</code>
 * uses <code>NumberFormat.getInstance</code> to format the argument; if the
 * argument is a <code>Date</code>, then <code>format</code> uses
 * <code>DateFormat.getDateTimeInstance</code> to format the argument.
 * Otherwise, it uses the <code>toString</code> method.
 *
 * <p>
 * For more sophisticated patterns, you can use a <code>ChoiceFormat</code> to get
 * output such as:
 * <blockquote>
 * <pre>
 * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
 * double[] filelimits = {0,1,2};
 * String[] filepart = {"no files","one file","{0,number} files"};
 * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
 * form.setFormat(1,fileform); // NOT zero, see below
 *
 * Object[] testArgs = {new Long(12373), "MyDisk"};
 *
 * System.out.println(form.format(testArgs));
 *
 * // output, with different testArgs
 * output: The disk "MyDisk" contains no files.
 * output: The disk "MyDisk" contains one file.
 * output: The disk "MyDisk" contains 1,273 files.
 * </pre>
 * </blockquote>
 * You can either do this programmatically, as in the above example,
 * or by using a pattern (see
 * <a href="java.text.ChoiceFormat.html"><code>ChoiceFormat</code></a>
 * for more information) as in:
 * <blockquote>
 * <pre>
 * form.applyPattern(
 *    "There {0,choice,0#are no files|1#is one file|1#are {0,number,integer} files}.");
 * </pre>
 * </blockquote>
 * <p>
 * <strong>Note:</strong> As we see above, the string produced
 * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated specially;
 * occurances of '{' are used to indicated subformats, and cause recursion.
 * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
 * programmatically (instead of using the string patterns), then be careful not to
 * produce a format that recurses on itself, which will cause an infinite loop.
 * <p>
 * <strong>Note:</strong> formats are numbered by order of
 * variable in the string.
 * This is <strong>not</strong> the same as the argument numbering!
 * For example: with "abc{2}def{3}ghi{0}...",
 * <ul>
 * <li>format0 affects the first variable {2}
 * <li>format1 affects the second variable {3}
 * <li>format2 affects the second variable {0}
 * <li>and so on.
 * </ul>
 * <p>
 * You can use <code>setLocale</code> followed by <code>applyPattern</code>
 * (and then possibly <code>setFormat</code>) to re-initialize a
 * <code>MessageFormat</code> with a different locale.
 *
 * @see          java.util.Locale
 * @see          Format
 * @see          NumberFormat
 * @see          DecimalFormat
 * @see          ChoiceFormat
 * @version      1.15 29 Jan 1997
 * @author       Mark Davis
 */

public class MessageFormat extends Format {
    /**
     * Constructs with the specified pattern.
     * @see MessageFormat#applyPattern
     */
    public MessageFormat(String pattern) {
        applyPattern(pattern);
    }

    /**
     * Constructs with the specified pattern and formats for the
     * arguments in that pattern.
     * @see MessageFormat#setPattern
     */
    public void setLocale(Locale theLocale) {
        String existingPattern = toPattern();                       /*ibm.3550*/
        locale = theLocale;
        applyPattern(existingPattern);                              /*ibm.3550*/
    }

    /**
     * Gets the locale. This locale is used for fetching default number or date
     * format information.
     */
    public Locale getLocale() {
        return locale;
    }


    /**
     * Sets the pattern. See the class description.
     */

    public void applyPattern(String newPattern) {
            StringBuffer[] segments = new StringBuffer[4];
            for (int i = 0; i < segments.length; ++i) {
                segments[i] = new StringBuffer();
            }
            int part = 0;
            int formatNumber = 0;
            boolean inQuote = false;
            int braceStack = 0;
            maxOffset = -1;
            for (int i = 0; i < newPattern.length(); ++i) {
                char ch = newPattern.charAt(i);
                if (part == 0) {
                    if (ch == '\'') {
                        if (i + 1 < newPattern.length()
                            && newPattern.charAt(i+1) == '\'') {
                            segments[part].append(ch);  // handle doubles
                            ++i;
                        } else {
                            inQuote = !inQuote;
                        }
                    } else if (ch == '{' && !inQuote) {
                        part = 1;
                    } else {
                        segments[part].append(ch);
                    }
                } else  if (inQuote) {              // just copy quotes in parts
                    segments[part].append(ch);
                    if (ch == '\'') {
                        inQuote = false;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?