9 |
|
|
10 |
public class CollationInterpreter |
public class CollationInterpreter |
11 |
{ |
{ |
|
static final int INVALID_OPERATOR = -1; |
|
|
static final int PRIMARY = 0; |
|
|
static final int SECONDARY = 1; |
|
|
static final int TERTIARY = 2; |
|
|
static final int IDENTICAL = 3; |
|
|
static final int RESET = 4; |
|
|
static final int EXPAND = 5; |
|
12 |
|
|
|
static final int IGNORABLE = 1; |
|
|
static final int NON_IGNORABLE = 2; |
|
|
static final int EXPANSION = 4; |
|
|
static final int FIRST_RESET = 8; |
|
|
|
|
13 |
class CollationElement |
class CollationElement |
14 |
{ |
{ |
|
int operator; |
|
15 |
String code; |
String code; |
|
boolean multiChar; |
|
|
int flags; |
|
16 |
CollationElement expand; |
CollationElement expand; |
17 |
|
int flags; |
18 |
|
boolean multiChar; |
19 |
|
int operator; |
20 |
CollationElement reset; |
CollationElement reset; |
21 |
} |
} |
22 |
|
static final int EXPAND = 5; |
23 |
|
static final int EXPANSION = 4; |
24 |
|
static final int FIRST_RESET = 8; |
25 |
|
static final int IDENTICAL = 3; |
26 |
|
static final int IGNORABLE = 1; |
27 |
|
static final int INVALID_OPERATOR = -1; |
28 |
|
static final int NON_IGNORABLE = 2; |
29 |
|
static final int PRIMARY = 0; |
30 |
|
static final int RESET = 4; |
31 |
|
static final int SECONDARY = 1; |
32 |
|
static final int TERTIARY = 2; |
33 |
|
|
34 |
|
private static String fixForRuleBasedCollator(String s) |
35 |
|
{ |
36 |
|
StringBuffer sbuf = null; |
37 |
|
boolean useSBUF = false; |
38 |
|
for (int i = 0; i < s.length(); i++) |
39 |
|
{ |
40 |
|
char c = s.charAt(i); |
41 |
|
if (!useSBUF) |
42 |
|
{ |
43 |
|
if ((c >= 0x0009 && c <= 0x000d) || (c >= 0x0020 && c <= 0x002F) |
44 |
|
|| (c >= 0x003A && c <= 0x0040) || (c >= 0x005B && c <= 0x0060) |
45 |
|
|| (c >= 0x007B && c <= 0x007E)) |
46 |
|
{ |
47 |
|
useSBUF = true; |
48 |
|
sbuf = new StringBuffer(); |
49 |
|
sbuf.append('\''); |
50 |
|
sbuf.append(s.substring(0, i + 1)); |
51 |
|
} |
52 |
|
} |
53 |
|
else |
54 |
|
{ |
55 |
|
if (s.charAt(i) == '\'') |
56 |
|
sbuf.append("''"); |
57 |
|
else |
58 |
|
sbuf.append(s.charAt(i)); |
59 |
|
} |
60 |
|
} |
61 |
|
if (useSBUF) |
62 |
|
{ |
63 |
|
sbuf.append('\''); |
64 |
|
return sbuf.toString(); |
65 |
|
} |
66 |
|
else |
67 |
|
return s; |
68 |
|
} |
69 |
|
|
70 |
|
private static char getJavaOperator(int operator) |
71 |
|
{ |
72 |
|
switch (operator) |
73 |
|
{ |
74 |
|
case PRIMARY: |
75 |
|
return '<'; |
76 |
|
case SECONDARY: |
77 |
|
return ';'; |
78 |
|
case TERTIARY: |
79 |
|
return ','; |
80 |
|
case IDENTICAL: |
81 |
|
return '='; |
82 |
|
default: |
83 |
|
throw new AssertionError("Invalid operator code " + operator); |
84 |
|
} |
85 |
|
} |
86 |
|
|
87 |
ArrayList collationData; |
ArrayList collationData; |
88 |
ArrayList expandedData = new ArrayList(); |
ArrayList expandedData = new ArrayList(); |
89 |
|
|
90 |
public CollationInterpreter(ArrayList data) |
public CollationInterpreter(ArrayList data) |
91 |
{ |
{ |
92 |
this.collationData = data; |
this.collationData = data; |
93 |
} |
} |
94 |
|
|
95 |
|
public void compute() |
96 |
|
{ |
97 |
|
if (collationData == null) |
98 |
|
return; |
99 |
|
expandData(); |
100 |
|
reorderData(); |
101 |
|
} |
102 |
|
|
103 |
/* |
/* |
104 |
* This method fills the CollationElement with the correct type and |
* This is the first pass. We translate the LDML rules and expand them a |
105 |
* type information according to name. If it is unknown, the type is |
* little further. The expansion involves pre-analysis of RESET rules and |
106 |
* assigned to INVALID_OPERATOR. |
* EXPAND rules. The output is an ordered array of collation rules with direct |
107 |
|
* access to expansion rules. |
108 |
|
*/ |
109 |
|
void expandData() |
110 |
|
{ |
111 |
|
Iterator collat = collationData.iterator(); |
112 |
|
int resetPosition; |
113 |
|
int lastNonIgnorable = 0; |
114 |
|
boolean newReset = true; |
115 |
|
CollationElement resetElement; |
116 |
|
resetElement = new CollationElement(); |
117 |
|
resetElement.code = ""; |
118 |
|
resetElement.flags |= FIRST_RESET; |
119 |
|
resetPosition = 0; |
120 |
|
while (collat.hasNext()) |
121 |
|
{ |
122 |
|
Element elt = (Element) collat.next(); |
123 |
|
CollationElement e = new CollationElement(); |
124 |
|
fillType(e, elt.qualifiedName); |
125 |
|
e.reset = resetElement; |
126 |
|
assert (e.operator != INVALID_OPERATOR); |
127 |
|
switch (e.operator) |
128 |
|
{ |
129 |
|
case EXPAND: |
130 |
|
{ |
131 |
|
/* |
132 |
|
* Here we consider the expand type elements. They have a rule |
133 |
|
* order specification (p, s, t, pc, sc, tc, i, ic) and an |
134 |
|
* <extend> attribute. If we get two valid ones, we produce an |
135 |
|
* Error. |
136 |
|
* |
137 |
|
* Here we transform an EXPAND operator into a COLLATION |
138 |
|
* operator and mark the rule as to be expanded. |
139 |
|
*/ |
140 |
|
ExpansionElement expandElement = (ExpansionElement) elt; |
141 |
|
e.expand = new CollationElement(); |
142 |
|
e.operator = INVALID_OPERATOR; |
143 |
|
e.flags |= EXPANSION; |
144 |
|
if (newReset) |
145 |
|
{ |
146 |
|
e.flags |= FIRST_RESET; |
147 |
|
newReset = false; |
148 |
|
} |
149 |
|
e.expand.code = expandElement.extendData; |
150 |
|
fillType(e, expandElement.extendOperator); |
151 |
|
assert (e.operator != INVALID_OPERATOR); |
152 |
|
e.code = expandElement.extendOperatorData; |
153 |
|
expandedData.add(resetPosition, e); |
154 |
|
resetPosition++; |
155 |
|
if (lastNonIgnorable < resetPosition) |
156 |
|
lastNonIgnorable++; |
157 |
|
break; |
158 |
|
} |
159 |
|
case RESET: |
160 |
|
{ |
161 |
|
/* |
162 |
|
* RESET needs also a special treatment. In Java, we have only |
163 |
|
* automatic expansion and position reset. LDML may specific |
164 |
|
* logical position reset: - various ignoreable positions - |
165 |
|
* various non-ignoreable positions - normal symbol ordered |
166 |
|
* reset (after or before) In the first case, we will place all |
167 |
|
* elements as ignoreable and that's all for Java. The second |
168 |
|
* case needs a bit of logic. |
169 |
|
*/ |
170 |
|
ResetElement reset = (ResetElement) elt; |
171 |
|
switch (reset.logicalReset) |
172 |
|
{ |
173 |
|
case ResetElement.FIRST_PRIMARY_IGNORABLE: |
174 |
|
case ResetElement.FIRST_SECONDARY_IGNORABLE: |
175 |
|
case ResetElement.FIRST_TERTIARY_IGNORABLE: |
176 |
|
case ResetElement.LAST_PRIMARY_IGNORABLE: |
177 |
|
case ResetElement.LAST_SECONDARY_IGNORABLE: |
178 |
|
case ResetElement.LAST_TERTIARY_IGNORABLE: |
179 |
|
e.flags |= IGNORABLE; |
180 |
|
resetPosition = 0; // All ignorables are in heading |
181 |
|
// position in Java. |
182 |
|
break; |
183 |
|
case ResetElement.LAST_NON_IGNORABLE: |
184 |
|
resetPosition = lastNonIgnorable; |
185 |
|
break; |
186 |
|
default: |
187 |
|
{ |
188 |
|
/* |
189 |
|
* We use in that case non-logical ordering We have to |
190 |
|
* do as in Java and parse the entire list to check |
191 |
|
* where to put the reset and the following elements. |
192 |
|
*/ |
193 |
|
assert (reset.data != null); |
194 |
|
assert (!reset.data.equals("")); |
195 |
|
resetElement.code = reset.data; |
196 |
|
for (int i = 0; i < expandedData.size(); i++) |
197 |
|
{ |
198 |
|
CollationElement ce = (CollationElement) expandedData |
199 |
|
.get(i); |
200 |
|
if (reset.data.equals(ce.code)) |
201 |
|
{ |
202 |
|
/* |
203 |
|
* We have found it ! Now we may have to move to |
204 |
|
* satisfy the "before" attribute. |
205 |
|
*/ |
206 |
|
// TODO TODO |
207 |
|
resetPosition = i; |
208 |
|
} |
209 |
|
} |
210 |
|
break; |
211 |
|
} |
212 |
|
} |
213 |
|
resetElement = e; |
214 |
|
break; |
215 |
|
} |
216 |
|
default: |
217 |
|
/* |
218 |
|
* This is the default handler. If this is a sequence we expand |
219 |
|
* the list into single operation (e.multiChar == true). We mark |
220 |
|
* the first of the sequence as being a FIRST_RESET sequence if a |
221 |
|
* reset element has been issued. |
222 |
|
*/ |
223 |
|
{ |
224 |
|
DataElement dat_elt = (DataElement) elt; |
225 |
|
if (e.multiChar) |
226 |
|
{ |
227 |
|
// We have to completely expand the rule here. |
228 |
|
for (int i = 0; i < dat_elt.data.length(); i++) |
229 |
|
{ |
230 |
|
CollationElement e2 = new CollationElement(); |
231 |
|
e2.code = Character.toString(dat_elt.data.charAt(i)); |
232 |
|
e2.flags = (e.flags | e.reset.flags) & ~FIRST_RESET; |
233 |
|
e2.reset = e.reset; |
234 |
|
e2.operator = e2.operator; |
235 |
|
if (newReset) |
236 |
|
{ |
237 |
|
e2.flags |= FIRST_RESET; |
238 |
|
newReset = false; |
239 |
|
} |
240 |
|
expandedData.add(resetPosition, e2); |
241 |
|
resetPosition++; |
242 |
|
} |
243 |
|
if (lastNonIgnorable < resetPosition) |
244 |
|
lastNonIgnorable += dat_elt.data.length(); |
245 |
|
} |
246 |
|
else |
247 |
|
{ |
248 |
|
e.code = dat_elt.data; |
249 |
|
e.flags = (e.flags | e.reset.flags) & ~FIRST_RESET; |
250 |
|
expandedData.add(resetPosition, e); |
251 |
|
resetPosition++; |
252 |
|
if (newReset) |
253 |
|
{ |
254 |
|
e.flags |= FIRST_RESET; |
255 |
|
newReset = false; |
256 |
|
} |
257 |
|
} |
258 |
|
if (lastNonIgnorable < resetPosition) |
259 |
|
lastNonIgnorable++; |
260 |
|
} |
261 |
|
break; |
262 |
|
} |
263 |
|
} |
264 |
|
/* |
265 |
|
* The collation data are now ready for reordering. |
266 |
|
*/ |
267 |
|
// Release the original array. |
268 |
|
collationData = null; |
269 |
|
} |
270 |
|
|
271 |
|
/* |
272 |
|
* This method fills the CollationElement with the correct type and type |
273 |
|
* information according to name. If it is unknown, the type is assigned to |
274 |
|
* INVALID_OPERATOR. |
275 |
*/ |
*/ |
276 |
void fillType(CollationElement e, String name) |
void fillType(CollationElement e, String name) |
277 |
{ |
{ |
278 |
int type; |
int type; |
279 |
boolean multiChar = false; |
boolean multiChar = false; |
|
|
|
280 |
if (name.equals("p")) |
if (name.equals("p")) |
281 |
{ |
{ |
282 |
type = PRIMARY; |
type = PRIMARY; |
283 |
multiChar = false; |
multiChar = false; |
284 |
} |
} |
285 |
else if (name.equals("s")) |
else if (name.equals("s")) |
286 |
{ |
{ |
287 |
type = SECONDARY; |
type = SECONDARY; |
288 |
multiChar = false; |
multiChar = false; |
289 |
} |
} |
290 |
else if (name.equals("t")) |
else if (name.equals("t")) |
291 |
{ |
{ |
292 |
type = TERTIARY; |
type = TERTIARY; |
293 |
multiChar = false; |
multiChar = false; |
294 |
} |
} |
295 |
else if (name.equals("i")) |
else if (name.equals("i")) |
296 |
{ |
{ |
297 |
type = IDENTICAL; |
type = IDENTICAL; |
298 |
multiChar = false; |
multiChar = false; |
299 |
} |
} |
300 |
else if (name.equals("pc")) |
else if (name.equals("pc")) |
301 |
{ |
{ |
302 |
type = PRIMARY; |
type = PRIMARY; |
303 |
multiChar = true; |
multiChar = true; |
304 |
} |
} |
305 |
else if (name.equals("sc")) |
else if (name.equals("sc")) |
306 |
{ |
{ |
307 |
type = SECONDARY; |
type = SECONDARY; |
308 |
multiChar = true; |
multiChar = true; |
309 |
} |
} |
310 |
else if (name.equals("tc")) |
else if (name.equals("tc")) |
311 |
{ |
{ |
312 |
type = TERTIARY; |
type = TERTIARY; |
313 |
multiChar = true; |
multiChar = true; |
314 |
} |
} |
315 |
else if (name.equals("ic")) |
else if (name.equals("ic")) |
316 |
{ |
{ |
317 |
type = IDENTICAL; |
type = IDENTICAL; |
318 |
multiChar = true; |
multiChar = true; |
319 |
} |
} |
320 |
else if (name.equals("reset")) |
else if (name.equals("reset")) |
321 |
{ |
{ |
322 |
type = RESET; |
type = RESET; |
323 |
multiChar = true; |
multiChar = true; |
324 |
} |
} |
325 |
else if (name.equals("x")) |
else if (name.equals("x")) |
326 |
{ |
{ |
327 |
type = EXPAND; |
type = EXPAND; |
328 |
} |
} |
329 |
else |
else |
330 |
type = INVALID_OPERATOR; |
type = INVALID_OPERATOR; |
|
|
|
331 |
e.operator = type; |
e.operator = type; |
332 |
e.multiChar = multiChar; |
e.multiChar = multiChar; |
333 |
} |
} |
334 |
|
|
335 |
/* |
/* |
336 |
* This is the first pass. We translate the LDML rules and expand them a little further. |
* expandData has taken care of placing all ignorable sequence at the begining |
337 |
* The expansion involves pre-analysis of RESET rules and EXPAND rules. |
* (for Java) and the rest after. All sequences are marked (IGNORABLE, |
338 |
* The output is an ordered array of collation rules with direct access to expansion rules. |
* NON_IGNORABLE or EXPAND). Here we will have to move EXPAND to the end and |
339 |
*/ |
* finish the complete expansion according to the context. |
340 |
void expandData() |
* |
341 |
{ |
* At that stage may also occur CONTRACTION when a context element has been |
342 |
Iterator collat = collationData.iterator(); |
* encountered. |
|
int resetPosition; |
|
|
int lastNonIgnorable = 0; |
|
|
boolean newReset = true; |
|
|
CollationElement resetElement; |
|
|
|
|
|
resetElement = new CollationElement(); |
|
|
resetElement.code = ""; |
|
|
resetElement.flags |= FIRST_RESET; |
|
|
resetPosition = 0; |
|
|
|
|
|
while (collat.hasNext()) |
|
|
{ |
|
|
Element elt = (Element)collat.next(); |
|
|
CollationElement e = new CollationElement(); |
|
|
|
|
|
fillType(e, elt.qualifiedName); |
|
|
|
|
|
e.reset = resetElement; |
|
|
|
|
|
assert (e.operator != INVALID_OPERATOR); |
|
|
|
|
|
switch (e.operator) { |
|
|
case EXPAND: |
|
|
{ |
|
|
/* |
|
|
* Here we consider the expand type elements. |
|
|
* They have a rule order specification (p, s, t, pc, sc, tc, i, ic) and |
|
|
* an <extend> attribute. If we get two valid ones, we produce an Error. |
|
|
* |
|
|
* Here we transform an EXPAND operator into a COLLATION operator and |
|
|
* mark the rule as to be expanded. |
|
|
*/ |
|
|
ExpansionElement expandElement = (ExpansionElement)elt; |
|
|
|
|
|
e.expand = new CollationElement(); |
|
|
e.operator = INVALID_OPERATOR; |
|
|
e.flags |= EXPANSION; |
|
|
|
|
|
if (newReset) |
|
|
{ |
|
|
e.flags |= FIRST_RESET; |
|
|
newReset = false; |
|
|
} |
|
|
|
|
|
e.expand.code = expandElement.extendData; |
|
|
fillType(e, expandElement.extendOperator); |
|
|
assert (e.operator != INVALID_OPERATOR); |
|
|
e.code = expandElement.extendOperatorData; |
|
|
|
|
|
expandedData.add(resetPosition, e); |
|
|
resetPosition++; |
|
|
if (lastNonIgnorable < resetPosition) |
|
|
lastNonIgnorable++; |
|
|
break; |
|
|
} |
|
|
case RESET: |
|
|
{ |
|
|
/* |
|
|
* RESET needs also a special treatment. |
|
|
* In Java, we have only automatic expansion and position reset. |
|
|
* LDML may specific logical position reset: |
|
|
* - various ignoreable positions |
|
|
* - various non-ignoreable positions |
|
|
* - normal symbol ordered reset (after or before) |
|
|
* In the first case, we will place all elements as ignoreable |
|
|
* and that's all for Java. The second case needs a bit of logic. |
|
|
*/ |
|
|
ResetElement reset = (ResetElement)elt; |
|
|
|
|
|
switch (reset.logicalReset) |
|
|
{ |
|
|
case ResetElement.FIRST_PRIMARY_IGNORABLE: |
|
|
case ResetElement.FIRST_SECONDARY_IGNORABLE: |
|
|
case ResetElement.FIRST_TERTIARY_IGNORABLE: |
|
|
case ResetElement.LAST_PRIMARY_IGNORABLE: |
|
|
case ResetElement.LAST_SECONDARY_IGNORABLE: |
|
|
case ResetElement.LAST_TERTIARY_IGNORABLE: |
|
|
e.flags |= IGNORABLE; |
|
|
resetPosition = 0; // All ignorables are in heading position in Java. |
|
|
break; |
|
|
case ResetElement.LAST_NON_IGNORABLE: |
|
|
resetPosition = lastNonIgnorable; |
|
|
break; |
|
|
default: |
|
|
{ |
|
|
/* We use in that case non-logical ordering |
|
|
* We have to do as in Java and parse the entire list |
|
|
* to check where to put the reset and the following elements. |
|
|
*/ |
|
|
assert (reset.data != null); |
|
|
assert (!reset.data.equals("")); |
|
|
|
|
|
resetElement.code = reset.data; |
|
|
for (int i = 0; i < expandedData.size(); i++) |
|
|
{ |
|
|
CollationElement ce = (CollationElement)expandedData.get(i); |
|
|
|
|
|
if (reset.data.equals(ce.code)) |
|
|
{ |
|
|
/* We have found it ! |
|
|
* Now we may have to move to satisfy the "before" attribute. |
|
|
*/ |
|
|
|
|
|
// TODO TODO |
|
|
resetPosition = i; |
|
|
} |
|
|
} |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
resetElement = e; |
|
|
break; |
|
|
} |
|
|
|
|
|
default: |
|
|
/* |
|
|
* This is the default handler. If this is a sequence we expand the list into |
|
|
* single operation (e.multiChar == true). We mark the first of the sequence as |
|
|
* being a FIRST_RESET sequence if a reset element has been issued. |
|
|
*/ |
|
|
{ |
|
|
DataElement dat_elt = (DataElement)elt; |
|
|
|
|
|
if (e.multiChar) |
|
|
{ |
|
|
// We have to completely expand the rule here. |
|
|
|
|
|
for (int i = 0; i < dat_elt.data.length(); i++) |
|
|
{ |
|
|
CollationElement e2 = new CollationElement(); |
|
|
|
|
|
e2.code = Character.toString(dat_elt.data.charAt(i)); |
|
|
e2.flags = (e.flags | e.reset.flags) & ~FIRST_RESET; |
|
|
e2.reset = e.reset; |
|
|
e2.operator = e2.operator; |
|
|
|
|
|
if (newReset) |
|
|
{ |
|
|
e2.flags |= FIRST_RESET; |
|
|
newReset = false; |
|
|
} |
|
|
expandedData.add(resetPosition, e2); |
|
|
resetPosition++; |
|
|
} |
|
|
if (lastNonIgnorable < resetPosition) |
|
|
lastNonIgnorable += dat_elt.data.length(); |
|
|
} |
|
|
else |
|
|
{ |
|
|
e.code = dat_elt.data; |
|
|
e.flags = (e.flags | e.reset.flags) & ~FIRST_RESET; |
|
|
expandedData.add(resetPosition, e); |
|
|
resetPosition++; |
|
|
|
|
|
if (newReset) |
|
|
{ |
|
|
e.flags |= FIRST_RESET; |
|
|
newReset = false; |
|
|
} |
|
|
} |
|
|
if (lastNonIgnorable < resetPosition) |
|
|
lastNonIgnorable++; |
|
|
} |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
/* |
|
|
* The collation data are now ready for reordering. |
|
|
*/ |
|
|
|
|
|
// Release the original array. |
|
|
collationData = null; |
|
|
} |
|
|
|
|
|
/* |
|
|
* expandData has taken care of placing all ignorable sequence at the begining (for Java) |
|
|
* and the rest after. All sequences are marked (IGNORABLE, NON_IGNORABLE or EXPAND). |
|
|
* Here we will have to move EXPAND to the end and finish the complete expansion according |
|
|
* to the context. |
|
|
* |
|
|
* At that stage may also occur CONTRACTION when a context element has been encountered. |
|
343 |
*/ |
*/ |
344 |
void reorderData() |
void reorderData() |
345 |
{ |
{ |
346 |
String sequence_context = null; |
String sequence_context = null; |
347 |
int originalSize = expandedData.size(); |
int originalSize = expandedData.size(); |
348 |
int i = 0; |
int i = 0; |
|
|
|
349 |
while (i < originalSize) |
while (i < originalSize) |
350 |
{ |
{ |
351 |
CollationElement ce = (CollationElement)expandedData.get(i); |
CollationElement ce = (CollationElement) expandedData.get(i); |
352 |
|
if ((ce.flags & EXPANSION) != 0 && (ce.flags & IGNORABLE) == 0) |
353 |
if ((ce.flags & EXPANSION) != 0 && (ce.flags & IGNORABLE) == 0) |
{ |
354 |
{ |
assert (sequence_context != null || (ce.reset.flags & FIRST_RESET) != 0); |
355 |
assert (sequence_context != null || (ce.reset.flags & FIRST_RESET) != 0); |
if ((ce.flags & FIRST_RESET) == 0) |
356 |
|
sequence_context = ce.reset.code; |
357 |
if ((ce.flags & FIRST_RESET) == 0) |
// We expand to remember the real position. |
358 |
sequence_context = ce.reset.code; |
ce.expand.code = sequence_context + ce.expand.code; |
359 |
|
// Now we move it to the end. |
360 |
// We expand to remember the real position. |
expandedData.remove(i); |
361 |
ce.expand.code = sequence_context + ce.expand.code; |
originalSize--; |
362 |
// Now we move it to the end. |
expandedData.add(ce); |
363 |
expandedData.remove(i); |
} |
364 |
originalSize--; |
else |
365 |
expandedData.add(ce); |
{ |
366 |
} |
sequence_context = ce.code; |
367 |
else |
i++; |
368 |
{ |
} |
|
sequence_context = ce.code; |
|
|
i++; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
public void compute() |
|
|
{ |
|
|
if (collationData == null) |
|
|
return; |
|
|
|
|
|
expandData(); |
|
|
reorderData(); |
|
|
} |
|
|
|
|
|
private static String fixForRuleBasedCollator(String s) |
|
|
{ |
|
|
StringBuffer sbuf = null; |
|
|
boolean useSBUF = false; |
|
|
|
|
|
for (int i = 0; i < s.length(); i++) |
|
|
{ |
|
|
char c = s.charAt(i); |
|
|
|
|
|
if (!useSBUF) |
|
|
{ |
|
|
if ((c >= 0x0009 && c <= 0x000d) || (c >= 0x0020 && c <= 0x002F) |
|
|
|| (c >= 0x003A && c <= 0x0040) || (c >= 0x005B && c <= 0x0060) |
|
|
|| (c >= 0x007B && c <= 0x007E)) |
|
|
{ |
|
|
useSBUF = true; |
|
|
sbuf = new StringBuffer(); |
|
|
sbuf.append('\''); |
|
|
sbuf.append(s.substring(0, i+1)); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
if (s.charAt(i) == '\'') |
|
|
sbuf.append("''"); |
|
|
else |
|
|
sbuf.append(s.charAt(i)); |
|
|
} |
|
|
} |
|
|
|
|
|
if (useSBUF) |
|
|
{ |
|
|
sbuf.append('\''); |
|
|
return sbuf.toString(); |
|
|
} |
|
|
else |
|
|
return s; |
|
|
} |
|
|
|
|
|
private static char getJavaOperator(int operator) |
|
|
{ |
|
|
switch (operator) |
|
|
{ |
|
|
case PRIMARY: |
|
|
return '<'; |
|
|
case SECONDARY: |
|
|
return ';'; |
|
|
case TERTIARY: |
|
|
return ','; |
|
|
case IDENTICAL: |
|
|
return '='; |
|
|
default: |
|
|
throw new AssertionError("Invalid operator code " + operator); |
|
369 |
} |
} |
370 |
} |
} |
371 |
|
|
374 |
Iterator iter = expandedData.iterator(); |
Iterator iter = expandedData.iterator(); |
375 |
boolean ignoreFinished = false; |
boolean ignoreFinished = false; |
376 |
StringBuffer sb = new StringBuffer(); |
StringBuffer sb = new StringBuffer(); |
|
|
|
377 |
while (iter.hasNext()) |
while (iter.hasNext()) |
378 |
{ |
{ |
379 |
CollationElement ce = (CollationElement)iter.next(); |
CollationElement ce = (CollationElement) iter.next(); |
380 |
|
if ((ce.reset.flags & IGNORABLE) != 0) |
381 |
if ((ce.reset.flags & IGNORABLE) != 0) |
{ |
382 |
{ |
// We don't know how to put EXPANSION in IGNORABLE atm. |
383 |
// We don't know how to put EXPANSION in IGNORABLE atm. |
assert ((ce.flags & EXPANSION) == 0); |
384 |
assert ((ce.flags & EXPANSION) == 0); |
assert (!ignoreFinished); |
385 |
assert (!ignoreFinished); |
sb.append('='); |
386 |
|
sb.append(fixForRuleBasedCollator(ce.code)); |
387 |
sb.append('='); |
} |
388 |
sb.append(fixForRuleBasedCollator(ce.code)); |
else if ((ce.flags & EXPANSION) != 0) |
389 |
} |
{ |
390 |
else if ((ce.flags & EXPANSION) != 0) |
ignoreFinished = true; |
391 |
{ |
sb.append('&'); |
392 |
ignoreFinished = true; |
sb.append(fixForRuleBasedCollator(ce.expand.code)); |
393 |
|
sb.append(getJavaOperator(ce.operator)); |
394 |
sb.append('&'); |
sb.append(fixForRuleBasedCollator(ce.code)); |
395 |
sb.append(fixForRuleBasedCollator(ce.expand.code)); |
} |
396 |
sb.append(getJavaOperator(ce.operator)); |
else |
397 |
sb.append(fixForRuleBasedCollator(ce.code)); |
{ |
398 |
} |
ignoreFinished = true; |
399 |
else |
sb.append(getJavaOperator(ce.operator)); |
400 |
{ |
sb.append(fixForRuleBasedCollator(ce.code)); |
401 |
ignoreFinished = true; |
} |
|
|
|
|
sb.append(getJavaOperator(ce.operator)); |
|
|
sb.append(fixForRuleBasedCollator(ce.code)); |
|
|
} |
|
402 |
} |
} |
|
|
|
403 |
return sb.toString(); |
return sb.toString(); |
404 |
} |
} |
405 |
} |
} |