SimpleFormatter.java

// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
 *******************************************************************************
 * Copyright (C) 2014-2016, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
package com.ibm.icu.text;

import com.ibm.icu.impl.SimpleFormatterImpl;

/**
 * Formats simple patterns like "{1} was born in {0}". Minimal subset of MessageFormat; fast,
 * simple, minimal dependencies. Supports only numbered arguments with no type nor style parameters,
 * and formats only string values. Quoting via ASCII apostrophe compatible with ICU MessageFormat
 * default behavior.
 *
 * <p>Factory methods throw exceptions for syntax errors and for too few or too many
 * arguments/placeholders.
 *
 * <p>SimpleFormatter objects are immutable and can be safely cached like strings.
 *
 * <p>Example:
 *
 * <pre>
 * SimpleFormatter fmt = SimpleFormatter.compile("{1} '{born}' in {0}");
 *
 * // Output: "paul {born} in england"
 * System.out.println(fmt.format("england", "paul"));
 * </pre>
 *
 * @see MessageFormat
 * @see MessagePattern.ApostropheMode
 * @stable ICU 57
 */
public final class SimpleFormatter {
    // For internal use in Java, use SimpleFormatterImpl directly instead:
    // It is most efficient to compile patterns to compiled-pattern strings
    // and use them with static methods.
    // (Avoids allocating SimpleFormatter wrapper objects.)

    /**
     * Binary representation of the compiled pattern.
     *
     * @see SimpleFormatterImpl
     */
    private final String compiledPattern;

    private SimpleFormatter(String compiledPattern) {
        this.compiledPattern = compiledPattern;
    }

    /**
     * Creates a formatter from the pattern string.
     *
     * @param pattern The pattern string.
     * @return The new SimpleFormatter object.
     * @throws IllegalArgumentException for bad argument syntax.
     * @stable ICU 57
     */
    public static SimpleFormatter compile(CharSequence pattern) {
        return compileMinMaxArguments(pattern, 0, Integer.MAX_VALUE);
    }

    /**
     * Creates a formatter from the pattern string. The number of arguments checked against the
     * given limits is the highest argument number plus one, not the number of occurrences of
     * arguments.
     *
     * @param pattern The pattern string.
     * @param min The pattern must have at least this many arguments.
     * @param max The pattern must have at most this many arguments.
     * @return The new SimpleFormatter object.
     * @throws IllegalArgumentException for bad argument syntax and too few or too many arguments.
     * @stable ICU 57
     */
    public static SimpleFormatter compileMinMaxArguments(CharSequence pattern, int min, int max) {
        StringBuilder sb = new StringBuilder();
        String compiledPattern =
                SimpleFormatterImpl.compileToStringMinMaxArguments(pattern, sb, min, max);
        return new SimpleFormatter(compiledPattern);
    }

    /**
     * @return The max argument number + 1.
     * @stable ICU 57
     */
    public int getArgumentLimit() {
        return SimpleFormatterImpl.getArgumentLimit(compiledPattern);
    }

    /**
     * Formats the given values.
     *
     * @stable ICU 57
     */
    public String format(CharSequence... values) {
        return SimpleFormatterImpl.formatCompiledPattern(compiledPattern, values);
    }

    /**
     * Formats the given values, appending to the appendTo builder.
     *
     * @param appendTo Gets the formatted pattern and values appended.
     * @param offsets offsets[i] receives the offset of where values[i] replaced pattern argument
     *     {i}. Can be null, or can be shorter or longer than values. If there is no {i} in the
     *     pattern, then offsets[i] is set to -1.
     * @param values The argument values. An argument value must not be the same object as appendTo.
     *     values.length must be at least getArgumentLimit(). Can be null if getArgumentLimit()==0.
     * @return appendTo
     * @stable ICU 57
     */
    public StringBuilder formatAndAppend(
            StringBuilder appendTo, int[] offsets, CharSequence... values) {
        return SimpleFormatterImpl.formatAndAppend(compiledPattern, appendTo, offsets, values);
    }

    /**
     * Formats the given values, replacing the contents of the result builder. May optimize by
     * actually appending to the result if it is the same object as the value corresponding to the
     * initial argument in the pattern.
     *
     * @param result Gets its contents replaced by the formatted pattern and values.
     * @param offsets offsets[i] receives the offset of where values[i] replaced pattern argument
     *     {i}. Can be null, or can be shorter or longer than values. If there is no {i} in the
     *     pattern, then offsets[i] is set to -1.
     * @param values The argument values. An argument value may be the same object as result.
     *     values.length must be at least getArgumentLimit().
     * @return result
     * @stable ICU 57
     */
    public StringBuilder formatAndReplace(
            StringBuilder result, int[] offsets, CharSequence... values) {
        return SimpleFormatterImpl.formatAndReplace(compiledPattern, result, offsets, values);
    }

    /**
     * Returns a string similar to the original pattern, only for debugging.
     *
     * @stable ICU 57
     */
    @Override
    public String toString() {
        String[] values = new String[getArgumentLimit()];
        for (int i = 0; i < values.length; i++) {
            values[i] = "{" + i + '}';
        }
        return formatAndAppend(new StringBuilder(), null, values).toString();
    }

    /**
     * Returns the pattern text with none of the arguments. Like formatting with all-empty string
     * values.
     *
     * @stable ICU 57
     */
    public String getTextWithNoArguments() {
        return SimpleFormatterImpl.getTextWithNoArguments(compiledPattern);
    }
}