2 *******************************************************************************
3 * Copyright (C) 2009-2012, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.text;
10 import java.util.ArrayList;
11 import java.util.Locale;
12 import java.util.MissingResourceException;
14 import com.ibm.icu.impl.ICUCache;
15 import com.ibm.icu.impl.ICUResourceBundle;
16 import com.ibm.icu.impl.SimpleCache;
17 import com.ibm.icu.lang.UCharacter;
18 import com.ibm.icu.util.ULocale;
19 import com.ibm.icu.util.ULocale.Category;
20 import com.ibm.icu.util.UResourceBundle;
21 import com.ibm.icu.util.UResourceBundleIterator;
25 * <code>NumberingSystem</code> is the base class for all number
26 * systems. This class provides the interface for setting different numbering
27 * system types, whether it be a simple alternate digit system such as
28 * Thai digits or Devanagari digits, or an algorithmic numbering system such
29 * as Hebrew numbering or Chinese numbering.
34 public class NumberingSystem {
37 * Default constructor. Returns a numbering system that uses the Western decimal
41 public NumberingSystem() {
49 * Factory method for creating a numbering system.
50 * @param radix_in The radix for this numbering system. ICU currently
51 * supports only numbering systems whose radix is 10.
52 * @param isAlgorithmic_in Specifies whether the numbering system is algorithmic
53 * (true) or numeric (false).
54 * @param desc_in String used to describe the characteristics of the numbering
55 * system. For numeric systems, this string contains the digits used by the
56 * numbering system, in order, starting from zero. For algorithmic numbering
57 * systems, the string contains the name of the RBNF ruleset in the locale's
58 * NumberingSystemRules section that will be used to format numbers using
59 * this numbering system.
62 public static NumberingSystem getInstance(int radix_in, boolean isAlgorithmic_in, String desc_in ) {
63 return getInstance(null,radix_in,isAlgorithmic_in,desc_in);
67 * Factory method for creating a numbering system.
68 * @param name_in The string representing the name of the numbering system.
69 * @param radix_in The radix for this numbering system. ICU currently
70 * supports only numbering systems whose radix is 10.
71 * @param isAlgorithmic_in Specifies whether the numbering system is algorithmic
72 * (true) or numeric (false).
73 * @param desc_in String used to describe the characteristics of the numbering
74 * system. For numeric systems, this string contains the digits used by the
75 * numbering system, in order, starting from zero. For algorithmic numbering
76 * systems, the string contains the name of the RBNF ruleset in the locale's
77 * NumberingSystemRules section that will be used to format numbers using
78 * this numbering system.
82 private static NumberingSystem getInstance(String name_in, int radix_in, boolean isAlgorithmic_in, String desc_in ) {
84 throw new IllegalArgumentException("Invalid radix for numbering system");
87 if ( !isAlgorithmic_in ) {
88 if ( desc_in.length() != radix_in || !isValidDigitString(desc_in)) {
89 throw new IllegalArgumentException("Invalid digit string for numbering system");
92 NumberingSystem ns = new NumberingSystem();
94 ns.algorithmic = isAlgorithmic_in;
101 * Returns the default numbering system for the specified locale.
104 public static NumberingSystem getInstance(Locale inLocale) {
105 return getInstance(ULocale.forLocale(inLocale));
109 * Returns the default numbering system for the specified ULocale.
112 public static NumberingSystem getInstance(ULocale locale) {
114 final String[] OTHER_NS_KEYWORDS = { "native", "traditional", "finance" };
117 Boolean nsResolved = true;
119 // Check for @numbers
120 String numbersKeyword = locale.getKeywordValue("numbers");
121 if (numbersKeyword != null ) {
122 for ( String keyword : OTHER_NS_KEYWORDS ) {
123 if ( numbersKeyword.equals(keyword)) {
129 numbersKeyword = "default";
134 ns = getInstanceByName(numbersKeyword);
137 } else { // if @numbers keyword points to a bogus numbering system name, we return the default for the locale
138 numbersKeyword = "default";
143 // Attempt to get the numbering system from the cache
144 String baseName = locale.getBaseName();
145 ns = cachedLocaleData.get(baseName+"@numbers="+numbersKeyword);
150 // Cache miss, create new instance
152 String originalNumbersKeyword = numbersKeyword;
153 String resolvedNumberingSystem = null;
154 while (!nsResolved) {
156 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,locale);
157 rb = rb.getWithFallback("NumberElements");
158 resolvedNumberingSystem = rb.getStringWithFallback(numbersKeyword);
160 } catch (MissingResourceException ex) { // Fall back behavior as defined in TR35
161 if (numbersKeyword.equals("native") || numbersKeyword.equals("finance")) {
162 numbersKeyword = "default";
163 } else if (numbersKeyword.equals("traditional")) {
164 numbersKeyword = "native";
171 if (resolvedNumberingSystem != null) {
172 ns = getInstanceByName(resolvedNumberingSystem);
176 ns = new NumberingSystem();
179 cachedLocaleData.put(baseName+"@numbers="+originalNumbersKeyword, ns);
185 * Returns the default numbering system for the default <code>FORMAT</code> locale.
186 * @see Category#FORMAT
189 public static NumberingSystem getInstance() {
190 return getInstance(ULocale.getDefault(Category.FORMAT));
194 * Returns a numbering system from one of the predefined numbering systems
195 * known to ICU. Numbering system names are based on the numbering systems
196 * defined in CLDR. To get a list of available numbering systems, use the
197 * getAvailableNames method.
198 * @param name The name of the desired numbering system. Numbering system
199 * names often correspond with the name of the script they are associated
200 * with. For example, "thai" for Thai digits, "hebr" for Hebrew numerals.
203 public static NumberingSystem getInstanceByName(String name) {
205 boolean isAlgorithmic;
208 // Get the numbering system from the cache
209 NumberingSystem ns = cachedStringData.get(name);
215 UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems");
216 UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems");
217 UResourceBundle nsTop = nsCurrent.get(name);
219 description = nsTop.getString("desc");
220 UResourceBundle nsRadixBundle = nsTop.get("radix");
221 UResourceBundle nsAlgBundle = nsTop.get("algorithmic");
222 radix = nsRadixBundle.getInt();
223 int algorithmic = nsAlgBundle.getInt();
225 isAlgorithmic = ( algorithmic == 1 );
227 } catch (MissingResourceException ex) {
231 ns = getInstance(name,radix,isAlgorithmic,description);
232 cachedStringData.put(name, ns);
237 * Returns a string array containing a list of the names of numbering systems
238 * currently known to ICU.
241 public static String [] getAvailableNames() {
243 UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems");
244 UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems");
245 UResourceBundle temp;
248 ArrayList<String> output = new ArrayList<String>();
249 UResourceBundleIterator it = nsCurrent.getIterator();
250 while (it.hasNext()) {
252 nsName = temp.getKey();
255 return output.toArray(new String[output.size()]);
259 * Convenience method to determine if a given digit string is valid for use as a
260 * descriptor of a numeric ( non-algorithmic ) numbering system. In order for
261 * a digit string to be valid, it must meet the following criteria:
262 * 1. Digits must be in Unicode's basic multilingual plane.
265 public static boolean isValidDigitString(String str) {
269 UCharacterIterator it = UCharacterIterator.getInstance(str);
272 while ( (c = it.nextCodePoint()) != UCharacterIterator.DONE) {
273 if ( UCharacter.isSupplementary(c)) { // Digits outside the BMP are not currently supported
285 * Returns the radix of the current numbering system.
288 public int getRadix() {
293 * Returns the description string of the current numbering system.
294 * The description string describes the characteristics of the numbering
295 * system. For numeric systems, this string contains the digits used by the
296 * numbering system, in order, starting from zero. For algorithmic numbering
297 * systems, the string contains the name of the RBNF ruleset in the locale's
298 * NumberingSystemRules section that will be used to format numbers using
299 * this numbering system.
302 public String getDescription() {
307 * Returns the string representing the name of the numbering system.
310 public String getName() {
314 * Returns the numbering system's algorithmic status. If true,
315 * the numbering system is algorithmic and uses an RBNF formatter to
316 * format numerals. If false, the numbering system is numeric and
317 * uses a fixed set of digits.
320 public boolean isAlgorithmic() {
326 private boolean algorithmic;
330 * Cache to hold the NumberingSystems by Locale.
332 private static ICUCache<String, NumberingSystem> cachedLocaleData = new SimpleCache<String, NumberingSystem>();
335 * Cache to hold the NumberingSystems by name.
337 private static ICUCache<String, NumberingSystem> cachedStringData = new SimpleCache<String, NumberingSystem>();