]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/text/NumberingSystem.java
Added flags.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / text / NumberingSystem.java
1 /*
2  *******************************************************************************
3  * Copyright (C) 2009-2012, International Business Machines Corporation and    *
4  * others. All Rights Reserved.                                                *
5  *******************************************************************************
6  */
7
8 package com.ibm.icu.text;
9
10 import java.util.ArrayList;
11 import java.util.Locale;
12 import java.util.MissingResourceException;
13
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;
22
23
24 /**
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.
30  *
31  * @author       John Emmons
32  * @stable ICU 4.2
33  */
34 public class NumberingSystem {
35
36     /**
37      * Default constructor.  Returns a numbering system that uses the Western decimal
38      * digits 0 through 9.
39      * @stable ICU 4.2
40      */
41     public NumberingSystem() {
42         radix = 10;
43         algorithmic = false;
44         desc = "0123456789";
45         name = "latn";
46     }
47
48     /**
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.
60      * @stable ICU 4.2
61      */
62     public static NumberingSystem getInstance(int radix_in, boolean isAlgorithmic_in, String desc_in ) {
63         return getInstance(null,radix_in,isAlgorithmic_in,desc_in);
64     }
65     
66     /**
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.
79      * @stable ICU 4.6
80      */
81    
82     private static NumberingSystem getInstance(String name_in, int radix_in, boolean isAlgorithmic_in, String desc_in ) {
83         if ( radix_in < 2 ) {
84             throw new IllegalArgumentException("Invalid radix for numbering system");
85         }
86
87         if ( !isAlgorithmic_in ) {
88             if ( desc_in.length() != radix_in || !isValidDigitString(desc_in)) {
89                 throw new IllegalArgumentException("Invalid digit string for numbering system");
90             }
91         }
92         NumberingSystem ns = new NumberingSystem();
93         ns.radix = radix_in;
94         ns.algorithmic = isAlgorithmic_in;
95         ns.desc = desc_in;
96         ns.name = name_in;
97         return ns;
98     }
99
100     /**
101      * Returns the default numbering system for the specified locale.
102      * @stable ICU 4.2
103      */
104     public static NumberingSystem getInstance(Locale inLocale) {
105         return getInstance(ULocale.forLocale(inLocale));
106     }
107
108     /**
109      * Returns the default numbering system for the specified ULocale.
110      * @stable ICU 4.2
111      */
112     public static NumberingSystem getInstance(ULocale locale) {
113         
114         final String[] OTHER_NS_KEYWORDS = { "native", "traditional", "finance" };
115  
116         NumberingSystem ns;
117         Boolean nsResolved = true;
118
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)) {
124                     nsResolved = false;
125                     break;
126                 }
127             }
128         } else {
129             numbersKeyword = "default";
130             nsResolved = false;
131         }
132
133         if (nsResolved) {
134             ns = getInstanceByName(numbersKeyword);
135             if ( ns != null ) {
136                 return ns;
137             } else { // if @numbers keyword points to a bogus numbering system name, we return the default for the locale
138                 numbersKeyword = "default";
139                 nsResolved = false;
140             }
141         }
142         
143         // Attempt to get the numbering system from the cache
144         String baseName = locale.getBaseName();
145         ns = cachedLocaleData.get(baseName+"@numbers="+numbersKeyword);
146         if (ns != null ) {
147             return ns;
148         }
149         
150         // Cache miss, create new instance
151
152         String originalNumbersKeyword = numbersKeyword;
153         String resolvedNumberingSystem = null;
154         while (!nsResolved) {           
155             try {
156                 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,locale);
157                 rb = rb.getWithFallback("NumberElements");
158                 resolvedNumberingSystem = rb.getStringWithFallback(numbersKeyword);
159                 nsResolved = true;
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";
165                  } else {
166                      nsResolved = true;
167                  }
168             }  
169         }
170
171         if (resolvedNumberingSystem != null) {
172             ns = getInstanceByName(resolvedNumberingSystem);
173         }
174         
175         if ( ns == null ) {
176             ns = new NumberingSystem();
177         }
178
179         cachedLocaleData.put(baseName+"@numbers="+originalNumbersKeyword, ns);
180         return ns;
181     
182     }
183
184     /**
185      * Returns the default numbering system for the default <code>FORMAT</code> locale.
186      * @see Category#FORMAT
187      * @stable ICU 4.2
188      */
189     public static NumberingSystem getInstance() {
190         return getInstance(ULocale.getDefault(Category.FORMAT));
191     }
192
193     /**
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.
201      * @stable ICU 4.2
202      */
203     public static NumberingSystem getInstanceByName(String name) {
204         int radix;
205         boolean isAlgorithmic;
206         String description;
207         
208         // Get the numbering system from the cache
209         NumberingSystem ns = cachedStringData.get(name);
210         if (ns != null ) {
211             return ns;
212         }        
213         
214         try {
215             UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems");
216             UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems");
217             UResourceBundle nsTop = nsCurrent.get(name);
218
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();
224
225             isAlgorithmic = ( algorithmic == 1 );
226
227         } catch (MissingResourceException ex) {
228             return null;
229         }
230
231         ns = getInstance(name,radix,isAlgorithmic,description);
232         cachedStringData.put(name, ns);                       
233         return ns;     
234     }
235
236     /**
237      * Returns a string array containing a list of the names of numbering systems
238      * currently known to ICU.
239      * @stable ICU 4.2
240      */
241     public static String [] getAvailableNames() {
242     
243             UResourceBundle numberingSystemsInfo = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "numberingSystems");
244             UResourceBundle nsCurrent = numberingSystemsInfo.get("numberingSystems");
245             UResourceBundle temp;
246
247             String nsName;
248             ArrayList<String> output = new ArrayList<String>();
249             UResourceBundleIterator it = nsCurrent.getIterator();
250             while (it.hasNext()) {
251                 temp = it.next();
252                 nsName = temp.getKey();
253                 output.add(nsName);
254             }
255             return output.toArray(new String[output.size()]);
256     }
257
258     /**
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.
263      * @stable ICU 4.2
264      */
265     public static boolean isValidDigitString(String str) {
266
267         int c;
268         int i = 0;
269         UCharacterIterator it = UCharacterIterator.getInstance(str);
270
271         it.setToStart();
272         while ( (c = it.nextCodePoint()) != UCharacterIterator.DONE) {
273             if ( UCharacter.isSupplementary(c)) { // Digits outside the BMP are not currently supported
274                 return false;
275             }
276             i++;
277         }
278         if ( i != 10 ) {
279             return false;
280         }
281         return true;
282     }
283
284     /**
285      * Returns the radix of the current numbering system.
286      * @stable ICU 4.2
287      */
288     public int getRadix() {
289         return radix;
290     }
291
292     /**
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.
300      * @stable ICU 4.2
301      */
302     public String getDescription() {
303         return desc;
304     }
305
306     /**
307      * Returns the string representing the name of the numbering system.
308      * @stable ICU 4.6
309      */
310     public String getName() {
311         return name;
312     }
313     /**
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. 
318      * @stable ICU 4.2
319      */
320     public boolean isAlgorithmic() {
321         return algorithmic;
322     }
323
324     private String desc;
325     private int radix;
326     private boolean algorithmic;
327     private String name;
328
329     /**
330      * Cache to hold the NumberingSystems by Locale.
331      */
332     private static ICUCache<String, NumberingSystem> cachedLocaleData = new SimpleCache<String, NumberingSystem>();
333         
334     /**
335      * Cache to hold the NumberingSystems by name.
336      */
337     private static ICUCache<String, NumberingSystem> cachedStringData = new SimpleCache<String, NumberingSystem>();
338     
339 }