| /* |
| ******************************************************************************* |
| * Copyright (C) 2009-2012, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| |
| package com.ibm.icu.text; |
| |
| import java.util.ArrayList; |
| import java.util.Locale; |
| 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.lang.UCharacter; |
| import com.ibm.icu.util.ULocale; |
| import com.ibm.icu.util.ULocale.Category; |
| import com.ibm.icu.util.UResourceBundle; |
| import com.ibm.icu.util.UResourceBundleIterator; |
| |
| |
| /** |
| * <code>NumberingSystem</code> is the base class for all number |
| * systems. This class provides the interface for setting different numbering |
| * system types, whether it be a simple alternate digit system such as |
| * Thai digits or Devanagari digits, or an algorithmic numbering system such |
| * as Hebrew numbering or Chinese numbering. |
| * |
| * @author John Emmons |
| * @stable ICU 4.2 |
| */ |
| public class NumberingSystem { |
| |
| /** |
| * Default constructor. Returns a numbering system that uses the Western decimal |
| * digits 0 through 9. |
| * @stable ICU 4.2 |
| */ |
| public NumberingSystem() { |
| radix = 10; |
| algorithmic = false; |
| desc = "0123456789"; |
| name = "latn"; |
| } |
| |
| /** |
| * Factory method for creating a numbering system. |
| * @param radix_in The radix for this numbering system. ICU currently |
| * supports only numbering systems whose radix is 10. |
| * @param isAlgorithmic_in Specifies whether the numbering system is algorithmic |
| * (true) or numeric (false). |
| * @param desc_in String used to describe the characteristics of the numbering |
| * system. For numeric systems, this string contains the digits used by the |
| * numbering system, in order, starting from zero. For algorithmic numbering |
| * systems, the string contains the name of the RBNF ruleset in the locale's |
| * NumberingSystemRules section that will be used to format numbers using |
| * this numbering system. |
| * @stable ICU 4.2 |
| */ |
| public static NumberingSystem getInstance(int radix_in, boolean isAlgorithmic_in, String desc_in ) { |
| return getInstance(null,radix_in,isAlgorithmic_in,desc_in); |
| } |
| |
| /** |
| * Factory method for creating a numbering system. |
| * @param name_in The string representing the name of the numbering system. |
| * @param radix_in The radix for this numbering system. ICU currently |
| * supports only numbering systems whose radix is 10. |
| * @param isAlgorithmic_in Specifies whether the numbering system is algorithmic |
| * (true) or numeric (false). |
| * @param desc_in String used to describe the characteristics of the numbering |
| * system. For numeric systems, this string contains the digits used by the |
| * numbering system, in order, starting from zero. For algorithmic numbering |
| * systems, the string contains the name of the RBNF ruleset in the locale's |
| * NumberingSystemRules section that will be used to format numbers using |
| * this numbering system. |
| * @stable ICU 4.6 |
| */ |
| |
| private static NumberingSystem getInstance(String name_in, int radix_in, boolean isAlgorithmic_in, String desc_in ) { |
| if ( radix_in < 2 ) { |
| throw new IllegalArgumentException("Invalid radix for numbering system"); |
| } |
| |
| if ( !isAlgorithmic_in ) { |
| if ( desc_in.length() != radix_in || !isValidDigitString(desc_in)) { |
| throw new IllegalArgumentException("Invalid digit string for numbering system"); |
| } |
| } |
| NumberingSystem ns = new NumberingSystem(); |
| ns.radix = radix_in; |
| ns.algorithmic = isAlgorithmic_in; |
| ns.desc = desc_in; |
| ns.name = name_in; |
| return ns; |
| } |
| |
| /** |
| * Returns the default numbering system for the specified locale. |
| * @stable ICU 4.2 |
| */ |
| public static NumberingSystem getInstance(Locale inLocale) { |
| return getInstance(ULocale.forLocale(inLocale)); |
| } |
| |
| /** |
| * Returns the default numbering system for the specified ULocale. |
| * @stable ICU 4.2 |
| */ |
| public static NumberingSystem getInstance(ULocale locale) { |
| |
| final String[] OTHER_NS_KEYWORDS = { "native", "traditional", "finance" }; |
| |
| NumberingSystem ns; |
| Boolean nsResolved = true; |
| |
| // Check for @numbers |
| String numbersKeyword = locale.getKeywordValue("numbers"); |
| if (numbersKeyword != null ) { |
| for ( String keyword : OTHER_NS_KEYWORDS ) { |
| if ( numbersKeyword.equals(keyword)) { |
| nsResolved = false; |
| break; |
| } |
| } |
| } else { |
| numbersKeyword = "default"; |
| nsResolved = false; |
| } |
| |
| if (nsResolved) { |
| ns = getInstanceByName(numbersKeyword); |
| if ( ns != null ) { |
| return ns; |
| } else { // if @numbers keyword points to a bogus numbering system name, we return the default for the locale |
| numbersKeyword = "default"; |
| nsResolved = false; |
| } |
| } |
| |
| // Attempt to get the numbering system from the cache |
| String baseName = locale.getBaseName(); |
| ns = cachedLocaleData.get(baseName+"@numbers="+numbersKeyword); |
| if (ns != null ) { |
| return ns; |
| } |
| |
| // Cache miss, create new instance |
| |
| String originalNumbersKeyword = numbersKeyword; |
| String resolvedNumberingSystem = null; |
| while (!nsResolved) { |
| try { |
| ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,locale); |
| rb = rb.getWithFallback("NumberElements"); |
| resolvedNumberingSystem = rb.getStringWithFallback(numbersKeyword); |
| nsResolved = true; |
| } catch (MissingResourceException ex) { // Fall back behavior as defined in TR35 |
| if (numbersKeyword.equals("native") || numbersKeyword.equals("finance")) { |
| numbersKeyword = "default"; |
| } else if (numbersKeyword.equals("traditional")) { |
| numbersKeyword = "native"; |
| } else { |
| nsResolved = true; |
| } |
| } |
| } |
| |
| if (resolvedNumberingSystem != null) { |
| ns = getInstanceByName(resolvedNumberingSystem); |
| } |
| |
| if ( ns == null ) { |
| ns = new NumberingSystem(); |
| } |
| |
| cachedLocaleData.put(baseName+"@numbers="+originalNumbersKeyword, ns); |
| return ns; |
| |
| } |
| |
| /** |
| * Returns the default numbering system for the default <code>FORMAT</code> locale. |
| * @see Category#FORMAT |
| * @stable ICU 4.2 |
| */ |
| public static NumberingSystem getInstance() { |
| return getInstance(ULocale.getDefault(Category.FORMAT)); |
| } |
| |
| /** |
| * Returns a numbering system from one of the predefined numbering systems |
| * known to ICU. Numbering system names are based on the numbering systems |
| * defined in CLDR. To get a list of available numbering systems, use the |
| * getAvailableNames method. |
| * @param name The name of the desired numbering system. Numbering system |
| * names often correspond with the name of the script they are associated |
| * with. For example, "thai" for Thai digits, "hebr" for Hebrew numerals. |
| * @stable ICU 4.2 |
| */ |
| public static NumberingSystem getInstanceByName(String name) { |
| int radix; |
| boolean isAlgorithmic; |
| String description; |
| |
| // Get the numbering system from the cache |
| NumberingSystem ns = cachedStringData.get(name); |
| if (ns != null ) { |
| return ns; |
| } |
| |
| try { |
| UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems"); |
| UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems"); |
| UResourceBundle nsTop = nsCurrent.get(name); |
| |
| description = nsTop.getString("desc"); |
| UResourceBundle nsRadixBundle = nsTop.get("radix"); |
| UResourceBundle nsAlgBundle = nsTop.get("algorithmic"); |
| radix = nsRadixBundle.getInt(); |
| int algorithmic = nsAlgBundle.getInt(); |
| |
| isAlgorithmic = ( algorithmic == 1 ); |
| |
| } catch (MissingResourceException ex) { |
| return null; |
| } |
| |
| ns = getInstance(name,radix,isAlgorithmic,description); |
| cachedStringData.put(name, ns); |
| return ns; |
| } |
| |
| /** |
| * Returns a string array containing a list of the names of numbering systems |
| * currently known to ICU. |
| * @stable ICU 4.2 |
| */ |
| public static String [] getAvailableNames() { |
| |
| UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems"); |
| UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems"); |
| UResourceBundle temp; |
| |
| String nsName; |
| ArrayList<String> output = new ArrayList<String>(); |
| UResourceBundleIterator it = nsCurrent.getIterator(); |
| while (it.hasNext()) { |
| temp = it.next(); |
| nsName = temp.getKey(); |
| output.add(nsName); |
| } |
| return output.toArray(new String[output.size()]); |
| } |
| |
| /** |
| * Convenience method to determine if a given digit string is valid for use as a |
| * descriptor of a numeric ( non-algorithmic ) numbering system. In order for |
| * a digit string to be valid, it must meet the following criteria: |
| * 1. Digits must be in Unicode's basic multilingual plane. |
| * @stable ICU 4.2 |
| */ |
| public static boolean isValidDigitString(String str) { |
| |
| int c; |
| int i = 0; |
| UCharacterIterator it = UCharacterIterator.getInstance(str); |
| |
| it.setToStart(); |
| while ( (c = it.nextCodePoint()) != UCharacterIterator.DONE) { |
| if ( UCharacter.isSupplementary(c)) { // Digits outside the BMP are not currently supported |
| return false; |
| } |
| i++; |
| } |
| if ( i != 10 ) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Returns the radix of the current numbering system. |
| * @stable ICU 4.2 |
| */ |
| public int getRadix() { |
| return radix; |
| } |
| |
| /** |
| * Returns the description string of the current numbering system. |
| * The description string describes the characteristics of the numbering |
| * system. For numeric systems, this string contains the digits used by the |
| * numbering system, in order, starting from zero. For algorithmic numbering |
| * systems, the string contains the name of the RBNF ruleset in the locale's |
| * NumberingSystemRules section that will be used to format numbers using |
| * this numbering system. |
| * @stable ICU 4.2 |
| */ |
| public String getDescription() { |
| return desc; |
| } |
| |
| /** |
| * Returns the string representing the name of the numbering system. |
| * @stable ICU 4.6 |
| */ |
| public String getName() { |
| return name; |
| } |
| /** |
| * Returns the numbering system's algorithmic status. If true, |
| * the numbering system is algorithmic and uses an RBNF formatter to |
| * format numerals. If false, the numbering system is numeric and |
| * uses a fixed set of digits. |
| * @stable ICU 4.2 |
| */ |
| public boolean isAlgorithmic() { |
| return algorithmic; |
| } |
| |
| private String desc; |
| private int radix; |
| private boolean algorithmic; |
| private String name; |
| |
| /** |
| * Cache to hold the NumberingSystems by Locale. |
| */ |
| private static ICUCache<String, NumberingSystem> cachedLocaleData = new SimpleCache<String, NumberingSystem>(); |
| |
| /** |
| * Cache to hold the NumberingSystems by name. |
| */ |
| private static ICUCache<String, NumberingSystem> cachedStringData = new SimpleCache<String, NumberingSystem>(); |
| |
| } |