Comparar Strings
Las aplicaciones que buscan u ordenan texto realizan frecuentes comparaciones. Por ejemplo, un navegador necesita comparar la igualdad de dos cadenas cuando los usuarios finales buscan algún texto. Un escritor de informes realiza comparaciones de cadenas cuando ordena un lista de cadenas en orden alfabético.
Si la audiencia de nuestra aplicación está limitada a personas de habla inglesa, probablemente podamos hacer las comparaciones con el método String.compareTo. Este método realiza una comparación binaria de caracteres Unicode dentro de las cadenas. Para muchos idiomas, esta comparación binaria no es suficiente para ordenar cadenas, porque los valores Unicode no corresponden con el orden relativo de los caracteres.
Afortunadamente, la clase Collator permite realizar comparaciones de cadenas en diferentes idiomas. En esta lección, veremos cómo utilizar la clase Collator para buscar y ordenar texto.
Realizar Comparaciones Independientes de la Localidad
Las reglas de comparación definen la secuencia de ordenación de los strings. Estas reglas pueden variar con la Localidad, porque los distintos idiomas naturales ordenan sus palabras de forma diferente. Utilizando las reglas predefinidas de la clase Collator, podemos ordenar cadenas de una forma independiente de la Localidad.
Se utiliza la clase Collator para realizar comparaciones independientes de la Localidad. Esta clase es sensible a la Localidad. Para ver las localidades soportadas por la clase Collator, se llama al método getAvailableLocales.
Locale[] locales = Collator.getAvailableLocales();
Para ejemplarizar la clase Collator, se llama al método getInstance y se especifica una Localidad.
Collator myCollator = Collator.getInstance(new Locale("en", "US"));
El método getInstance realmente devuelve un RuleBasedCollator, que es una subclase concreta de Collator. El objeto RuleBasedCollator contiene un conjunto de reglas que determinan el orden de ordenación de las cadenas para una localidad especificada. Estas reglas están predefinidas para cada localidad. Como estas reglas están encapsuladas dentro de RuleBasedCollator, los programas no necesitarán rutinas especiales para tratar con las reglas de comparación para varios idiomas.
Se llama al método Collator.compare para realizar comparaciones de cadenas independientes de la Localidad. Este método devuelve un entero menor que, igual que o mayor que cero cuando la cadena del primer argumento sea menor que, igual que o mayor que la cadena del segundo argumento.
System.out.println(myCollator.compare("abc", "def"));
System.out.println(myCollator.compare("rtf", "rtf"));
System.out.println(myCollator.compare("xyz", "abc"));
Aqui puedes ver la salida del programa anterior.
-1
0
1
Utilizaremos el método compare para realizar operaciones de ordenación. El programa de ejemplo, llamado CollatorDemo.java utiliza el método compare para ordenar un array de palabras Inglesas y Francesas. En este programa, veremos lo que sucede cuando se ordena un array con dos objetos Collator diferentes.
Collator fr_FRCollator = Collator.getInstance(new Locale("fr","FR"));
Collator en_USCollator = Collator.getInstance(new Locale("en","US"));
Nuestro método para ordenar, llamado sortStrings, puede ser utilizado con cualquier Collator. Observa que el método sortStrings llama al método compare.
public static void sortStrings(Collator collator, String[] words) {
String tmp;
for (int i = 0; i < words.length; i++) {
for (int j = i + 1; j < words.length; j++) {
// Compare elements of the array two at a time.
if (collator.compare(words[i], words[j] ) > 0 ) {
// Swap words[i] and words[j]
tmp = words[i];
words[i] = words[j];
words[j] = tmp;
}
}
}
}
El Collator Inglés ordena las palabras de esta forma.
peach
pêche
péché
sin
De acuerdo a las reglas de comparación del idioma Francés, la lista anterior sería errónea. En Francés, "pêche" debería seguir a "péché" en una lista ordenada. Nuestro Collator Francés ordena del array de forma correcta.
peach
péché
pêche
sin
Personalizar la Reglas de Comparación
En algunos casos, las reglas predefinidas de comparación proporcionadas por la clase Collator podrían no ser suficiente. Por ejemplo, podríamos querer ordenar strings en un idioma cuya localidad no estuviera soportada por Collator. En esta situación, podemos definir nuestras propias reglas de comparación, y asignarlas a un objeto RuleBasedCollator.
En la sección anterior, explicamos como realizar comparaciones de cadenas utilizando diferentes reglas para cada localidad. Estas reglas de comparación determinan el orden de ordenación de las cadenas. Si las reglas predefinidas no son suficientes, podemos diseñar nuestras propias reglas y asignarlas a un objeto
RuleBasedCollator.
Las reglas de comparación personalizadas están contenidas en un objeto String que se pasa al constructor de RuleBasedCollator. Aquí tenemos un ejemplo.
String simpleRule = "< a < b < c < d";
RuleBasedCollator simpleCollator = new RuleBasedCollator(simpleRule);
Para el objeto simpleCollator del ejemplo anterior, "a" es menor que "b," que es menor que "c," y así sucesivamente. El método simpleCollator.compare se referirá a estas reglas cuando compare cadenas. La síntaxis completa utilizada para construir una regla de comparación es más flexible y completa que ese sencillo ejemplo. Para una completa descripción de la síntaxis, puedes ver a la documentación del API para la clase RuleBasedCollator.
En el siguiente ejemplo ordenamos una lista de palabras españolas con dos objetos Collators. El código completo de este ejemplo está en el fichero llamado RulesDemo.java.
Empezamos definiendo nuestras propias reglas de ordenación para Inglés y Español. Hemos decidido ordenar las palabras en Español de la forma tradicional. Cuando se ordena de esta forma, las letras "ch," y "ll," y sus mayúsculas equivalentes. tienen su propia posición en el orden de ordenación. Estas parejas de caracteres se comparan como si fueran un sólo caracter. Por ejemplo, "ch" ordena com una sóla letra después de "cz". Observa las diferencias para los dos Collators.
String englishRules =
("< a,A < b,B < c,C < d,D < e,E < f,F " +
"< g,G < h,H < i,I < j,J < k,K < l,L " +
"< m,M < n,N < o,O < p,P < q,Q < r,R " +
"< s,S < t,T < u,U < v,V < w,W < x,X " +
"< y,Y < z,Z");
String smallnTilde = new String("\u00F1");
String capitalNTilde = new String("\u00D1");
String traditionalSpanishRules =
("< a,A < b,B < c,C " +
"< ch, cH, Ch, CH " +
"< d,D < e,E < f,F " +
"< g,G < h,H < i,I < j,J < k,K < l,L " +
"< ll, lL, Ll, LL " +
"< m,M < n,N " +
"< " + smallnTilde + "," + capitalNTilde + " " +
"< o,O < p,P < q,Q < r,R " +
"< s,S < t,T < u,U < v,V < w,W < x,X " +
"< y,Y < z,Z");
En las siguientes líneas de código, creamos los Collators y llamamos a nuestra rutina de ordenación.
try {
RuleBasedCollator enCollator =
new RuleBasedCollator(englishRules);
RuleBasedCollator spCollator =
new RuleBasedCollator(traditionalSpanishRules);
sortStrings(enCollator, words);
printStrings(words);
System.out.println();
sortStrings(spCollator, words);
printStrings(words);
}
catch (ParseException pe) {
System.out.println("Parse exception for rules");
}
La rutina de ordenación, llamada sortStrings, es genérica. Ordena cualquier array de palabras de acuerdo a las reglas de cualquier objeto Collator.
public static void sortStrings(Collator collator, String[] words) {
String tmp;
for (int i = 0; i < words.length; i++) {
for (int j = i + 1; j < words.length; j++) {
// Compare elements of the words array
if( collator.compare(words[i], words[j] ) > 0 ) {
// Swap words[i] and words[j]
tmp = words[i];
words[i] = words[j];
words[j] = tmp;
}
}
}
}
Cuando ordenamos con las reglas de ordenación Inglesas el array aparecerá de esta forma.
chalina
curioso
llama
luz
Compara la lista anterior con la siguiente, que está ordenada de acuerdo a las reglas de ordenación del Español tradicional.
curioso
chalina
luz
llama
Aumentar el Rendimiento de la Comparación
Con la clase CollationKey, podremos incrementar la eficiencia de la comparación de cadenas. Esta clase convierte objetos String a claves cortas que siguen las reglas de un objeto Collator dado.
La ordenación de largas listas de palabras consume mucho tiempo. Si el algoritmo de ordenación compara cadenas repetidamente podemos acelerar el proceso utilizando la clase CollationKey.
Un objeto CollationKey representa una clave de ordenación para un String y un Collator dados. Comparar dos objetos CollationKey envuelve una amplica comparación de claves cortas que es más rápido que comparar objetos String con el método Collator.compare. Sin embargo, generar objetos CollationKey también necesita tiempo. Por lo tanto, si un String sólo va a ser comparado una vez, Collator.compare ofrece mejor rendimiento.
En el siguiente ejemplo, utilizamos un objeto CollationKey para ordenar un array de palabras. El código completo de este ejemplo está en el fichero llamado KeysDemo.java.
Creamos un array de objetos CollationKey en el método main. Para crear un CollationKey, se llama al método getCollationKey sobre un objeto Collator. No se pueden comparar dos objetos CollationKey que no sean originales del mismo objeto Collator. Aqui podemos ver el método main.
static public void main(String[] args) {
Collator enUSCollator = Collator.getInstance(new Locale("en","US"));
String [] words = {
"peach",
"apricot",
"grape",
"lemon"
};
CollationKey[] keys = new CollationKey[words.length];
for (int k = 0; k < keys.length; k ++) {
keys[k] = enUSCollator.getCollationKey(words[k]);
}
sortArray(keys);
printArray(keys);
}
El método sortArray llama al método CollationKey.compareTo. Este método devuelve un entero menor que, igual que, o mayor que cero si el objeto keys[i] es menor que, igual que o mayor que el objeto keys[j]. Observa que hemos comparado los objetos CollationKey, no los objetos String del array original de palabras. Aquí puedes ver el código del método sortArray.
public static void sortArray(CollationKey[] keys) {
CollationKey tmp;
for (int i = 0; i < keys.length; i++) {
for (int j = i + 1; j < keys.length; j++) {
// Compare the keys
if( keys[i].compareTo( keys[j] ) > 0 ) {
// Swap keys[i] and keys[j]
tmp = keys[i];
keys[i] = keys[j];
keys[j] = tmp;
}
}
}
}
Hemos ordenado un array de objetosCollationKey, pero nuestro objetivo original era ordenar un array de objetos String. Para recuperar el String que representa a cada objeto CollationKey, llamamos al método getSourceString en el método displayWords.
static void displayWords(CollationKey[] keys) {
for (int i = 0; i < keys.length; i++) {
System.out.println(keys[i].getSourceString() + " ");
}
}
El método displayWords imprime las siguientes líneas.
apricot
grape
lemon
peach