KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > number > Numberer_en


1 package com.icl.saxon.number;
2
3 /**
4   * Class Numberer_en does number formatting for language="en".
5   * This supports the xsl:number element.
6   * Methods and data are declared as protected, and static is avoided, to allow easy subclassing.
7   * @author <A HREF="mailto:mhkay@iclway.co.uk>Michael H. Kay</A>
8   * @version 4 August 2000
9   */

10
11 public class Numberer_en implements Numberer {
12
13     /**
14     * Format a number into a string
15     * @param number The number to be formatted
16     * @param picture The format specification. This is a single component of the format attribute
17     * of xsl:number, e.g. "1", "01", "i", or "a"
18     * @param groupSize number of digits per group (0 implies no grouping)
19     * @param groupSeparator string to appear between groups of digits
20     * @param letterValue as defined in xsl:number ("alphabetic" or "traditional" or "")
21     * @return the formatted number
22     */

23
24     public String JavaDoc format(int number, String JavaDoc picture,
25                                  int groupSize, String JavaDoc groupSeparator,
26                                  String JavaDoc letterValue) {
27
28         if (number<=0) return "" + number; // not covered by the XSLT spec
29

30         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
31         char formchar = picture.charAt(0);
32
33         switch(formchar) {
34
35         case '0':
36         case '1':
37             sb.append(toRadical(number, westernDigits, picture, groupSize, groupSeparator));
38             break;
39
40         case 'A':
41             sb.append(toAlphaSequence(number, latinUpper));
42             break;
43
44         case 'a':
45             sb.append(toAlphaSequence(number, latinLower));
46             break;
47
48         case 'i':
49             if (letterValue.equals("alphabetic")) {
50                 alphaDefault(number, formchar, sb);
51             } else {
52                 sb.append(toRoman(number));
53             }
54             break;
55
56         case 'I':
57             if (letterValue.equals("alphabetic")) {
58                 alphaDefault(number, formchar, sb);
59             } else {
60                 sb.append(toRoman(number).toUpperCase());
61             }
62             break;
63
64         case 'o':
65             if (picture.equals("one")) {
66                 sb.append(toWords(number));
67             } else {
68                 alphaDefault(number, formchar, sb);
69             }
70             break;
71
72         case 'O':
73             if (picture.equals("ONE")) {
74                 sb.append(toWords(number).toUpperCase());
75             } else {
76                 alphaDefault(number, formchar, sb);
77             }
78             break;
79
80         case '\u0391':
81             sb.append(toAlphaSequence(number, greekUpper));
82             break;
83             
84         case '\u03b1':
85             sb.append(toAlphaSequence(number, greekLower));
86             break;
87
88         case '\u0410':
89             sb.append(toAlphaSequence(number, cyrillicUpper));
90             break;
91             
92         case '\u0430':
93             sb.append(toAlphaSequence(number, cyrillicLower));
94             break;
95
96         case '\u05d0':
97             sb.append(toAlphaSequence(number, hebrew));
98             break;
99
100         case '\u3042':
101             sb.append(toAlphaSequence(number, hiraganaA));
102             break;
103             
104         case '\u30a2':
105             sb.append(toAlphaSequence(number, katakanaA));
106             break;
107
108         case '\u3044':
109             sb.append(toAlphaSequence(number, hiraganaI));
110             break;
111
112         case '\u30a4':
113             sb.append(toAlphaSequence(number, katakanaI));
114             break;
115
116         case '\u4e00':
117             sb.append(toRadical(number, kanjiDigits, picture, groupSize, groupSeparator));
118             break;
119
120         default:
121
122             if (Character.isDigit(formchar)) {
123
124                 int zero = (int)formchar - Character.getNumericValue(formchar);
125                 String JavaDoc digits = "" +
126                     (char)(zero) +
127                     (char)(zero+1) +
128                     (char)(zero+2) +
129                     (char)(zero+3) +
130                     (char)(zero+4) +
131                     (char)(zero+5) +
132                     (char)(zero+6) +
133                     (char)(zero+7) +
134                     (char)(zero+8) +
135                     (char)(zero+9);
136
137                 sb.append(toRadical(number, digits, picture, groupSize, groupSeparator));
138                 break;
139         
140             } else {
141                 if (formchar < '\u1100') {
142                     alphaDefault(number, formchar, sb);
143                 } else {
144                     // fallback to western numbering
145
sb.append(
146                         toRadical(number, westernDigits, picture, groupSize, groupSeparator));
147                 }
148                 break;
149            
150             }
151         }
152         
153         return sb.toString();
154     }
155
156
157     protected String JavaDoc westernDigits =
158         "0123456789";
159
160     protected String JavaDoc latinUpper =
161         "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
162
163     protected String JavaDoc latinLower =
164         "abcdefghijklmnopqrstuvwxyz";
165
166     protected String JavaDoc greekUpper =
167         "\u0391\u0392\u0393\u0394\u0395\u0396\u0397\u0398\u0399\u039a" +
168         "\u039b\u039c\u039c\u039d\u039e\u039f\u03a0\u03a1\u03a3\u03a4" +
169         "\u03a5\u03a6\u03a7\u03a8\u03a9";
170
171     protected String JavaDoc greekLower =
172         "\u03b1\u03b2\u03b3\u03b4\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba" +
173         "\u03bb\u03bc\u03bc\u03bd\u03be\u03bf\u03c0\u03c1\u03c3\u03c4" +
174         "\u03c5\u03c6\u03c7\u03c8\u03c9";
175
176     // Cyrillic information from Dmitry Kirsanov [dmitry@kirsanov.com]
177
// (based on his personal knowledge of Russian texts, not any authoritative source)
178

179     protected String JavaDoc cyrillicUpper =
180         "\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418" +
181         "\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0421\u0423" +
182         "\u0424\u0425\u0426\u0427\u0428\u0429\u042b\u042d\u042e\u042f";
183
184     protected String JavaDoc cyrillicLower =
185         "\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438" +
186         "\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0441\u0443" +
187         "\u0444\u0445\u0446\u0447\u0448\u0449\u044b\u044d\u044e\u044f";
188
189     protected String JavaDoc hebrew =
190         "\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05db\u05dc" +
191         "\u05de\u05e0\u05e1\u05e2\u05e4\u05e6\u05e7\u05e8\u05e9\u05ea";
192         
193
194     // The following Japanese sequences were supplied by
195
// MURAKAMI Shinyu [murakami@nadita.com]
196

197     protected String JavaDoc hiraganaA =
198         "\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3053" +
199         "\u3055\u3057\u3059\u305b\u305d\u305f\u3061\u3064\u3066\u3068" +
200         "\u306a\u306b\u306c\u306d\u306e\u306f\u3072\u3075\u3078\u307b" +
201         "\u307e\u307f\u3080\u3081\u3082\u3084\u3086\u3088\u3089\u308a" +
202         "\u308b\u308c\u308d\u308f\u3092\u3093";
203
204     protected String JavaDoc katakanaA =
205
206         "\u30a2\u30a4\u30a6\u30a8\u30aa\u30ab\u30ad\u30af\u30b1\u30b3" +
207         "\u30b5\u30b7\u30b9\u30bb\u30bd\u30bf\u30c1\u30c4\u30c6\u30c8" +
208         "\u30ca\u30cb\u30cc\u30cd\u30ce\u30cf\u30d2\u30d5\u30d8\u30db" +
209         "\u30de\u30df\u30e0\u30e1\u30e2\u30e4\u30e6\u30e8\u30e9\u30ea" +
210         "\u30eb\u30ec\u30ed\u30ef\u30f2\u30f3";
211
212     protected String JavaDoc hiraganaI =
213
214         "\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c" +
215         "\u308b\u3092\u308f\u304b\u3088\u305f\u308c\u305d\u3064\u306d" +
216         "\u306a\u3089\u3080\u3046\u3090\u306e\u304a\u304f\u3084\u307e" +
217         "\u3051\u3075\u3053\u3048\u3066\u3042\u3055\u304d\u3086\u3081" +
218         "\u307f\u3057\u3091\u3072\u3082\u305b\u3059";
219
220     protected String JavaDoc katakanaI =
221     
222         "\u30a4\u30ed\u30cf\u30cb\u30db\u30d8\u30c8\u30c1\u30ea\u30cc" +
223         "\u30eb\u30f2\u30ef\u30ab\u30e8\u30bf\u30ec\u30bd\u30c4\u30cd" +
224         "\u30ca\u30e9\u30e0\u30a6\u30f0\u30ce\u30aa\u30af\u30e4\u30de" +
225         "\u30b1\u30d5\u30b3\u30a8\u30c6\u30a2\u30b5\u30ad\u30e6\u30e1" +
226         "\u30df\u30b7\u30f1\u30d2\u30e2\u30bb\u30b9";
227
228
229     protected String JavaDoc kanjiDigits =
230         "\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d";
231     
232
233     /**
234     * Default processing with an alphabetic format token: use the contiguous
235     * range of Unicode letters starting with that token.
236     */

237
238     protected void alphaDefault(int number, char formchar, StringBuffer JavaDoc sb) {
239         int min = (int)formchar;
240         int max = (int)formchar;
241         // use the contiguous range of letters starting with the specified one
242
while (Character.isLetterOrDigit((char)(max+1))) max++;
243         sb.append(toAlpha(number, min, max));
244     }
245
246     /**
247     * Format the number as an alphabetic label using the alphabet consisting
248     * of consecutive Unicode characters from min to max
249     */

250
251     protected String JavaDoc toAlpha(int number, int min, int max) {
252         if (number<=0) return "" + number;
253         int range = max - min + 1;
254         char last = (char)(((number-1) % range) + min);
255         if (number>range) {
256             return toAlpha((number-1)/range, min, max) + last;
257         } else {
258             return "" + last;
259         }
260     }
261
262     /**
263     * Convert the number into an alphabetic label using a given alphabet.
264     * For example, if the alphabet is "xyz" the sequence is x, y, z, xx, xy, xz, ....
265     */

266
267     protected String JavaDoc toAlphaSequence(int number, String JavaDoc alphabet) {
268         if (number<=0) return "" + number;
269         int range = alphabet.length();
270         char last = alphabet.charAt((number-1) % range);
271         if (number>range) {
272             return toAlphaSequence((number-1)/range, alphabet) + last;
273         } else {
274             return "" + last;
275         }
276     }
277
278     /**
279     * Convert the number into a decimal or other representation using the given set of
280     * digits.
281     * For example, if the digits are "01" the sequence is 1, 10, 11, 100, 101, 110, 111, ...
282     * @param number the number to be formatted
283     * @param digits the set of digits to be used
284     * @param picture the formatting token, e.g. 001 means include leading zeroes to give at least
285     * three decimal places
286     * @param groupsize the number of digits in each group
287     * @param groupSeparator the separator to use between groups of digits.
288     */

289
290     protected String JavaDoc toRadical(int number, String JavaDoc digits, String JavaDoc picture,
291                                  int groupSize, String JavaDoc groupSeparator) {
292                                     
293         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
294         StringBuffer JavaDoc temp = new StringBuffer JavaDoc();
295         int base = digits.length();
296         
297         String JavaDoc s = "";
298         int n = number;
299         while (n>0) {
300             s = digits.charAt(n % base) + s;
301             n = n / base;
302         }
303             
304         for (int i=0; i<(picture.length()-s.length()); i++) {
305             temp.append(digits.charAt(0));
306         }
307         temp.append(s);
308         
309         if (groupSize>0) {
310             for (int i=0; i<temp.length(); i++) {
311                 if (i!=0 && ((temp.length()-i) % groupSize) == 0) {
312                     sb.append(groupSeparator);
313                 }
314                 sb.append(temp.charAt(i));
315             }
316         } else {
317             sb = temp;
318         }
319
320         return sb.toString();
321     }
322
323     /**
324     * Generate a Roman numeral (in lower case)
325     */

326
327     protected String JavaDoc toRoman(int n) {
328         if (n<=0 || n>9999) return "" + n;
329         return romanThousands[n/1000] +
330                romanHundreds[(n/100) % 10] +
331                romanTens[(n/10) % 10] +
332                romanUnits[n % 10];
333     }
334
335     // Roman numbers beyond 4000 use overlining and other conventions which we won't
336
// attempt to reproduce. We'll go high enough to handle present-day Gregorian years.
337

338     private static String JavaDoc[] romanThousands =
339         {"", "m", "mm", "mmm", "mmmm", "mmmmm", "mmmmmm", "mmmmmmm", "mmmmmmmm", "mmmmmmmmm"};
340     private static String JavaDoc[] romanHundreds =
341         {"", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm"};
342     private static String JavaDoc[] romanTens =
343         {"", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc"};
344     private static String JavaDoc[] romanUnits =
345         {"", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix"};
346
347
348     /**
349     * Show the number as English words
350     */

351
352     public String JavaDoc toWords(int number) {
353         if (number >= 1000000000) {
354             return toWords(number / 1000000000) + " billion " + toWords(number % 1000000000);
355         } else if (number >= 1000000) {
356             return toWords(number / 1000000) + " million " + toWords(number % 1000000);
357         } else if (number >= 1000) {
358             return toWords(number / 1000) + " thousand " + toWords(number % 1000);
359         } else if (number >= 100) {
360             int rem = number % 100;
361             return toWords(number / 100) + " hundred" +
362                 (rem==0 ? "" : " and " + toWords(rem));
363         } else {
364             if (number < 20) return englishUnits[number];
365             int rem = number % 10;
366             return englishTens[number / 10] +
367                 (rem==0 ? "" : " " + englishUnits[rem]);
368         }
369     }
370
371     protected String JavaDoc[] englishUnits = {
372         "", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
373         "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
374         "seventeen", "eighteen", "nineteen"};
375
376     protected String JavaDoc[] englishTens = {
377         "", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
378         
379         
380
381 }
382
383 //
384
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
385
// you may not use this file except in compliance with the License. You may obtain a copy of the
386
// License at http://www.mozilla.org/MPL/
387
//
388
// Software distributed under the License is distributed on an "AS IS" basis,
389
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
390
// See the License for the specific language governing rights and limitations under the License.
391
//
392
// The Original Code is: all this file.
393
//
394
// The Initial Developer of the Original Code is
395
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
396
//
397
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
398
//
399
// Contributor(s): none.
400
//
401
Popular Tags