2
* Licensed to the Apache Software Foundation (ASF) under one
3
* or more contributor license agreements. See the NOTICE file
4
* distributed with this work for additional information
5
* regarding copyright ownership. The ASF licenses this file
6
* to you under the Apache License, Version 2.0 (the "License");
7
* you may not use this file except in compliance with the License.
8
* You may obtain a copy of the License at
10
* http://www.apache.org/licenses/LICENSE-2.0
12
* Unless required by applicable law or agreed to in writing, software
13
* distributed under the License is distributed on an "AS IS" BASIS,
14
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
* See the License for the specific language governing permissions and
16
* limitations under the License.
19
* $Id: StringComparable.java,v 1.2 2009/12/10 03:18:23 matthewoliver Exp $
22
package org.apache.xml.utils;
24
import java.util.Vector;
25
import java.text.Collator;
26
import java.text.RuleBasedCollator;
27
import java.text.CollationElementIterator;
28
import java.util.Locale;
29
import java.text.CollationKey;
33
* International friendly string comparison with case-order
34
* @author Igor Hersht, igorh@ca.ibm.com
36
public class StringComparable implements Comparable {
38
public final static int UNKNOWN_CASE = -1;
39
public final static int UPPER_CASE = 1;
40
public final static int LOWER_CASE = 2;
42
private String m_text;
43
private Locale m_locale;
44
private RuleBasedCollator m_collator;
45
private String m_caseOrder;
46
private int m_mask = 0xFFFFFFFF;
48
public StringComparable(final String text, final Locale locale, final Collator collator, final String caseOrder){
51
m_collator = (RuleBasedCollator)collator;
52
m_caseOrder = caseOrder;
53
m_mask = getMask(m_collator.getStrength());
56
public final static Comparable getComparator( final String text, final Locale locale, final Collator collator, final String caseOrder){
57
if((caseOrder == null) ||(caseOrder.length() == 0)){// no case-order specified
58
return ((RuleBasedCollator)collator).getCollationKey(text);
60
return new StringComparable(text, locale, collator, caseOrder);
64
public final String toString(){return m_text;}
66
public int compareTo(Object o) {
67
final String pattern = ((StringComparable)o).toString();
68
if(m_text.equals(pattern)){//Code-point equals
71
final int savedStrength = m_collator.getStrength();
73
// Is there difference more significant than case-order?
74
if(((savedStrength == Collator.PRIMARY) || (savedStrength == Collator.SECONDARY))){
75
comp = m_collator.compare(m_text, pattern );
76
}else{// more than SECONDARY
77
m_collator.setStrength(Collator.SECONDARY);
78
comp = m_collator.compare(m_text, pattern );
79
m_collator.setStrength(savedStrength);
81
if(comp != 0){//Difference more significant than case-order
85
// No difference more significant than case-order.
86
// Find case difference
87
comp = getCaseDiff(m_text, pattern);
90
}else{// No case differences. Less significant difference could exist
91
return m_collator.compare(m_text, pattern );
96
private final int getCaseDiff (final String text, final String pattern){
97
final int savedStrength = m_collator.getStrength();
98
final int savedDecomposition = m_collator.getDecomposition();
99
m_collator.setStrength(Collator.TERTIARY);// not to ignore case
100
m_collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION );// corresponds NDF
102
final int diff[] =getFirstCaseDiff (text, pattern, m_locale);
103
m_collator.setStrength(savedStrength);// restore
104
m_collator.setDecomposition(savedDecomposition); //restore
106
if((m_caseOrder).equals("upper-first")){
107
if(diff[0] == UPPER_CASE){
113
if(diff[0] == LOWER_CASE){
119
}else{// No case differences
127
private final int[] getFirstCaseDiff(final String text, final String pattern, final Locale locale){
129
final CollationElementIterator targIter = m_collator.getCollationElementIterator(text);
130
final CollationElementIterator patIter = m_collator.getCollationElementIterator(pattern);
135
final int done = getElement(CollationElementIterator.NULLORDER);
136
int patternElement = 0, targetElement = 0;
137
boolean getPattern = true, getTarget = true;
141
startPatt = patIter.getOffset();
142
patternElement = getElement(patIter.next());
143
endPatt = patIter.getOffset();
146
startTarg = targIter.getOffset();
147
targetElement = getElement(targIter.next());
148
endTarg = targIter.getOffset();
150
getTarget = getPattern = true;
151
if ((patternElement == done) ||( targetElement == done)) {
153
} else if (targetElement == 0) {
155
} else if (patternElement == 0) {
157
} else if (targetElement != patternElement) {// mismatch
158
if((startPatt < endPatt) && (startTarg < endTarg)){
159
final String subText = text.substring(startTarg, endTarg);
160
final String subPatt = pattern.substring(startPatt, endPatt);
161
final String subTextUp = subText.toUpperCase(locale);
162
final String subPattUp = subPatt.toUpperCase(locale);
163
if(m_collator.compare(subTextUp, subPattUp) != 0){ // not case diffference
167
int diff[] = {UNKNOWN_CASE, UNKNOWN_CASE};
168
if(m_collator.compare(subText, subTextUp) == 0){
169
diff[0] = UPPER_CASE;
170
}else if(m_collator.compare(subText, subText.toLowerCase(locale)) == 0){
171
diff[0] = LOWER_CASE;
173
if(m_collator.compare(subPatt, subPattUp) == 0){
174
diff[1] = UPPER_CASE;
175
}else if(m_collator.compare(subPatt, subPatt.toLowerCase(locale)) == 0){
176
diff[1] = LOWER_CASE;
179
if(((diff[0] == UPPER_CASE) && ( diff[1] == LOWER_CASE)) ||
180
((diff[0] == LOWER_CASE) && ( diff[1] == UPPER_CASE))){
182
}else{// not case diff
195
// Return a mask for the part of the order we're interested in
196
private static final int getMask(final int strength) {
198
case Collator.PRIMARY:
200
case Collator.SECONDARY:
206
//get collation element with given strength
207
// from the element with max strength
208
private final int getElement(int maxStrengthElement){
210
return (maxStrengthElement & m_mask);