All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ibm.icu.text.ListFormatter Maven / Gradle / Ivy

Go to download

International Component for Unicode for Java (ICU4J) is a mature, widely used Java library providing Unicode and Globalization support

There is a newer version: 76.1
Show newest version
/*
 *******************************************************************************
 * Copyright (C) 2012-2014, Google, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
package com.ibm.icu.text;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;

import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.impl.SimpleCache;
import com.ibm.icu.impl.SimplePatternFormatter;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;

/**
 * Immutable class for formatting a list, using data from CLDR (or supplied
 * separately). The class is not subclassable.
 *
 * @author Mark Davis
 * @stable ICU 50
 */
final public class ListFormatter {
    private final SimplePatternFormatter two;
    private final SimplePatternFormatter start;
    private final SimplePatternFormatter middle;
    private final SimplePatternFormatter end;
    private final ULocale locale;
    
    /**
     * Indicates the style of Listformatter
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public enum Style {
        /**
         * Standard style.
         * @internal
         * @deprecated This API is ICU internal only.
         */
        @Deprecated
        STANDARD("standard"),
        /**
         * Style for full durations
         * @internal
         * @deprecated This API is ICU internal only.
         */
        @Deprecated
        DURATION("unit"),
        /**
         * Style for durations in abbrevated form
         * @internal
         * @deprecated This API is ICU internal only.
         */
        @Deprecated
        DURATION_SHORT("unit-short"),
        /**
         * Style for durations in narrow form
         * @internal
         * @deprecated This API is ICU internal only.
         */
        @Deprecated
        DURATION_NARROW("unit-narrow");
        
        private final String name;
        
        Style(String name) {
            this.name = name;
        }
        /**
         * @internal
         * @deprecated This API is ICU internal only.
         */
        @Deprecated
        public String getName() {
            return name;
        }
        
    }

    /**
     * Internal: Create a ListFormatter from component strings,
     * with definitions as in LDML.
     *
     * @param two
     *            string for two items, containing {0} for the first, and {1}
     *            for the second.
     * @param start
     *            string for the start of a list items, containing {0} for the
     *            first, and {1} for the rest.
     * @param middle
     *            string for the start of a list items, containing {0} for the
     *            first part of the list, and {1} for the rest of the list.
     * @param end
     *            string for the end of a list items, containing {0} for the
     *            first part of the list, and {1} for the last item.
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public ListFormatter(String two, String start, String middle, String end) {
        this(
                SimplePatternFormatter.compile(two),
                SimplePatternFormatter.compile(start),
                SimplePatternFormatter.compile(middle),
                SimplePatternFormatter.compile(end),
                null);
        
    }
    
    private ListFormatter(SimplePatternFormatter two, SimplePatternFormatter start, SimplePatternFormatter middle, SimplePatternFormatter end, ULocale locale) {
        this.two = two;
        this.start = start;
        this.middle = middle;
        this.end = end;
        this.locale = locale;
    }

    /**
     * Create a list formatter that is appropriate for a locale.
     *
     * @param locale
     *            the locale in question.
     * @return ListFormatter
     * @stable ICU 50
     */
    public static ListFormatter getInstance(ULocale locale) {
      return getInstance(locale, Style.STANDARD);
    }

    /**
     * Create a list formatter that is appropriate for a locale.
     *
     * @param locale
     *            the locale in question.
     * @return ListFormatter
     * @stable ICU 50
     */
    public static ListFormatter getInstance(Locale locale) {
        return getInstance(ULocale.forLocale(locale), Style.STANDARD);
    }
    
    /**
     * Create a list formatter that is appropriate for a locale and style.
     *
     * @param locale the locale in question.
     * @param style the style
     * @return ListFormatter
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public static ListFormatter getInstance(ULocale locale, Style style) {
        return cache.get(locale, style.getName());
    }

    /**
     * Create a list formatter that is appropriate for the default FORMAT locale.
     *
     * @return ListFormatter
     * @stable ICU 50
     */
    public static ListFormatter getInstance() {
        return getInstance(ULocale.getDefault(ULocale.Category.FORMAT));
    }

    /**
     * Format a list of objects.
     *
     * @param items
     *            items to format. The toString() method is called on each.
     * @return items formatted into a string
     * @stable ICU 50
     */
    public String format(Object... items) {
        return format(Arrays.asList(items));
    }

    /**
     * Format a collection of objects. The toString() method is called on each.
     *
     * @param items
     *            items to format. The toString() method is called on each.
     * @return items formatted into a string
     * @stable ICU 50
     */
    public String format(Collection items) {
        // TODO optimize this for the common case that the patterns are all of the
        // form {0}{1}.
        // We avoid MessageFormat, because there is no "sub" formatting.
        return format(items, -1).toString();
    }
    
    // Formats a collection of objects and returns the formatted string plus the offset
    // in the string where the index th element appears. index is zero based. If index is
    // negative or greater than or equal to the size of items then this function returns -1 for
    // the offset.
    FormattedListBuilder format(Collection items, int index) {
        Iterator it = items.iterator();
        int count = items.size();
        switch (count) {
        case 0:
            return new FormattedListBuilder("", false);
        case 1:
            return new FormattedListBuilder(it.next(), index == 0);
        case 2:
            return new FormattedListBuilder(it.next(), index == 0).append(two, it.next(), index == 1);
        }
        FormattedListBuilder builder = new FormattedListBuilder(it.next(), index == 0);
        builder.append(start, it.next(), index == 1);
        for (int idx = 2; idx < count - 1; ++idx) {
            builder.append(middle, it.next(), index == idx);
        }
        return builder.append(end, it.next(), index == count - 1);
    }
    
    /**
     * Returns the pattern to use for a particular item count.
     * @param count the item count.
     * @return the pattern with {0}, {1}, {2}, etc. For English,
     * getPatternForNumItems(3) == "{0}, {1}, and {2}"
     * @throws IllegalArgumentException when count is 0 or negative.
     * @stable ICU 52
     */
    public String getPatternForNumItems(int count) {
        if (count <= 0) {
            throw new IllegalArgumentException("count must be > 0");
        }
        ArrayList list = new ArrayList();
        for (int i = 0; i < count; i++) {
            list.add(String.format("{%d}", i));
        }
        return format(list);
    }
    
    /**
     * Returns the locale of this object.
     * @internal
     * @deprecated This API is ICU internal only.
     */
    @Deprecated
    public ULocale getLocale() {
        return locale;
    }
    
    // Builds a formatted list
    static class FormattedListBuilder {
        private StringBuilder current;
        private int offset;
        
        // Start is the first object in the list; If recordOffset is true, records the offset of
        // this first object.
        public FormattedListBuilder(Object start, boolean recordOffset) {
            this.current = new StringBuilder(start.toString());
            this.offset = recordOffset ? 0 : -1;
        }
        
        // Appends additional object. pattern is a template indicating where the new object gets
        // added in relation to the rest of the list. {0} represents the rest of the list; {1}
        // represents the new object in pattern. next is the object to be added. If recordOffset
        // is true, records the offset of next in the formatted string.
        public FormattedListBuilder append(SimplePatternFormatter pattern, Object next, boolean recordOffset) {
            if (pattern.getPlaceholderCount() != 2) {
                throw new IllegalArgumentException("Need {0} and {1} only in pattern " + pattern);
            }
           int[] offsets = (recordOffset || offsetRecorded()) ? new int[2] : null;
           StringBuilder nextBuilder =
                   pattern.startsWithPlaceholder(0) ? current : new StringBuilder();
           current = pattern.format(
                   nextBuilder, offsets, current, next.toString());
           if (offsets != null) {
               if (offsets[0] == -1 || offsets[1] == -1) {
                   throw new IllegalArgumentException(
                           "{0} or {1} missing from pattern " + pattern);
               }
               if (recordOffset) {
                   offset = offsets[1];
               } else {
                   offset += offsets[0];
               }
           }
           return this;
        }

        @Override
        public String toString() {
            return current.toString();
        }
        
        // Gets the last recorded offset or -1 if no offset recorded.
        public int getOffset() {
            return offset;
        }
        
        private boolean offsetRecorded() {
            return offset >= 0;
        }
    }

    /** JUST FOR DEVELOPMENT */
    // For use with the hard-coded data
    // TODO Replace by use of RB
    // Verify in building that all of the patterns contain {0}, {1}.

    static Map localeToData = new HashMap();
    static void add(String locale, String...data) {
        localeToData.put(new ULocale(locale), new ListFormatter(data[0], data[1], data[2], data[3]));
    }

    private static class Cache {
        private final ICUCache cache =
            new SimpleCache();

        public ListFormatter get(ULocale locale, String style) {
            String key = String.format("%s:%s", locale.toString(), style);
            ListFormatter result = cache.get(key);
            if (result == null) {
                result = load(locale, style);
                cache.put(key, result);
            }
            return result;
        }

        private static ListFormatter load(ULocale ulocale, String style) {
            ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
                    getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, ulocale);
            // TODO(Travis Keep): This try-catch is a hack to cover missing aliases
            // for listPattern/duration and listPattern/duration-narrow in root.txt.
            try {
                return new ListFormatter(
                    SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/2").getString()),
                    SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/start").getString()),
                    SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/middle").getString()),
                    SimplePatternFormatter.compile(r.getWithFallback("listPattern/" + style + "/end").getString()),
                    ulocale);
            } catch (MissingResourceException e) {
                return new ListFormatter(
                        SimplePatternFormatter.compile(r.getWithFallback("listPattern/standard/2").getString()),
                        SimplePatternFormatter.compile(r.getWithFallback("listPattern/standard/start").getString()),
                        SimplePatternFormatter.compile(r.getWithFallback("listPattern/standard/middle").getString()),
                        SimplePatternFormatter.compile(r.getWithFallback("listPattern/standard/end").getString()),
                        ulocale);
            }
        }
    }

    static Cache cache = new Cache();
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy