KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibm > icu > text > TitlecaseTransliterator


1 /*
2  * Copyright (C) 1996-2005, International Business Machines Corporation and
3  * others. All Rights Reserved.
4  *
5  */

6 package com.ibm.icu.text;
7
8 import java.io.IOException JavaDoc;
9
10 import com.ibm.icu.impl.UCaseProps;
11
12 import com.ibm.icu.util.ULocale;
13
14 import com.ibm.icu.text.ReplaceableContextIterator;
15
16 /**
17  * A transliterator that converts all letters (as defined by
18  * <code>UCharacter.isLetter()</code>) to lower case, except for those
19  * letters preceded by non-letters. The latter are converted to title
20  * case using <code>UCharacter.toTitleCase()</code>.
21  * @author Alan Liu
22  */

23 class TitlecaseTransliterator extends Transliterator {
24
25     static final String JavaDoc _ID = "Any-Title";
26
27     /**
28      * System registration hook.
29      */

30     static void register() {
31         Transliterator.registerFactory(_ID, new Transliterator.Factory() {
32             public Transliterator getInstance(String JavaDoc ID) {
33                 return new TitlecaseTransliterator(ULocale.US);
34             }
35         });
36
37         registerSpecialInverse("Title", "Lower", false);
38     }
39
40     private ULocale locale;
41
42     private UCaseProps csp;
43     private ReplaceableContextIterator iter;
44     private StringBuffer JavaDoc result;
45     private int[] locCache;
46
47    /**
48      * Constructs a transliterator.
49      */

50     public TitlecaseTransliterator(ULocale loc) {
51         super(_ID, null);
52         locale = loc;
53         // Need to look back 2 characters in the case of "can't"
54
setMaximumContextLength(2);
55         try {
56             csp=UCaseProps.getSingleton();
57         } catch (IOException JavaDoc e) {
58             csp=null;
59         }
60         iter=new ReplaceableContextIterator();
61         result = new StringBuffer JavaDoc();
62         int[] locCache = new int[1];
63         locCache[0]=0;
64     }
65      
66     /**
67      * Implements {@link Transliterator#handleTransliterate}.
68      */

69     protected void handleTransliterate(Replaceable text,
70                                        Position offsets, boolean isIncremental) {
71         // TODO reimplement, see ustrcase.c
72
// using a real word break iterator
73
// instead of just looking for a transition between cased and uncased characters
74
// call CaseMapTransliterator::handleTransliterate() for lowercasing? (set fMap)
75
// needs to take isIncremental into account because case mappings are context-sensitive
76
// also detect when lowercasing function did not finish because of context
77

78         if (offsets.start >= offsets.limit) {
79             return;
80         }
81
82         // case type: >0 cased (UCaseProps.LOWER etc.) ==0 uncased <0 case-ignorable
83
int type;
84
85         // Our mode; we are either converting letter toTitle or
86
// toLower.
87
boolean doTitle = true;
88
89         // Determine if there is a preceding context of cased case-ignorable*,
90
// in which case we want to start in toLower mode. If the
91
// prior context is anything else (including empty) then start
92
// in toTitle mode.
93
int c, start;
94         for (start = offsets.start - 1; start >= offsets.contextStart; start -= UTF16.getCharCount(c)) {
95             c = text.char32At(start);
96             type=csp.getTypeOrIgnorable(c);
97             if(type>0) { // cased
98
doTitle=false;
99                 break;
100             } else if(type==0) { // uncased but not ignorable
101
break;
102             }
103             // else (type<0) case-ignorable: continue
104
}
105
106         // Convert things after a cased character toLower; things
107
// after a uncased, non-case-ignorable character toTitle. Case-ignorable
108
// characters are copied directly and do not change the mode.
109

110         iter.setText(text);
111         iter.setIndex(offsets.start);
112         iter.setLimit(offsets.limit);
113         iter.setContextLimits(offsets.contextStart, offsets.contextLimit);
114
115         result.setLength(0);
116
117         // Walk through original string
118
// If there is a case change, modify corresponding position in replaceable
119
int delta;
120
121         while((c=iter.nextCaseMapCP())>=0) {
122             type=csp.getTypeOrIgnorable(c);
123             if(type>=0) { // not case-ignorable
124
if(doTitle) {
125                     c=csp.toFullTitle(c, iter, result, locale, locCache);
126                 } else {
127                     c=csp.toFullLower(c, iter, result, locale, locCache);
128                 }
129                 doTitle = type==0; // doTitle=isUncased
130

131                 if(iter.didReachLimit() && isIncremental) {
132                     // the case mapping function tried to look beyond the context limit
133
// wait for more input
134
offsets.start=iter.getCaseMapCPStart();
135                     return;
136                 }
137
138                 /* decode the result */
139                 if(c<0) {
140                     /* c mapped to itself, no change */
141                     continue;
142                 } else if(c<=UCaseProps.MAX_STRING_LENGTH) {
143                     /* replace by the mapping string */
144                     delta=iter.replace(result.toString());
145                     result.setLength(0);
146                 } else {
147                     /* replace by single-code point mapping */
148                     delta=iter.replace(UTF16.valueOf(c));
149                 }
150
151                 if(delta!=0) {
152                     offsets.limit += delta;
153                     offsets.contextLimit += delta;
154                 }
155             }
156         }
157         offsets.start = offsets.limit;
158     }
159 }
160
Popular Tags