2011-12-05 7 views
15

Todos sabemos que usar el método equals() de String para la comparación de igualdad fallará miserablemente. En su lugar, se debe usar Collator, así:¿Dónde puedo encontrar un conjunto específico de reglas de intercalación para la comparación de igualdad de cadenas?

// we need to detect User Interface locale somehow 
Locale uiLocale = Locale.forLanguageTag("da-DK"); 
// Setting up collator object 
Collator collator = Collator.getInstance(uiLocale); 
collator.setStrength(Collator.SECONDARY); 
collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION); 
// strings for equality testing 
String test1 = "USA lover Grækenland støtte"; 
String test2 = "USA lover graekenland støtte"; 
boolean result = collator.equals(test1, test2); 

Ahora, este código funciona, es decir el resultado se da menos UILocale se establece en danés. En tal caso, dará falso. Desde luego, entiendo por qué esto sucedió: esto es sólo porque el método es igual se implementa como esto:

return compare(s1, s2) == Collator.Equal; 

Este método llama al que se utiliza para clasificar y comprobar si las cadenas son iguales. No lo son, porque las reglas de intercalación específicas danesas requieren que æ se ordenen después (si entiendo correctamente el resultado del método de comparación) ae. Sin embargo, estas cadenas son realmente lo mismo, con esta resistencia tanto las diferencias de casos como los caracteres de compatibilidad (así se llama) deben tratarse como iguales.

Para solucionar esto, uno usaría RuleBasedCollator con un conjunto específico de reglas que funcionarán para el caso de igualdad.
Finalmente, la pregunta es: ¿alguien sabe dónde puedo obtener tales reglas específicas (no solo para el danés, sino también para otros idiomas), para que los caracteres de compatibilidad, ligaduras, etc. sean tratados como iguales (CLDRchart no parece para contener tal o he fallado en buscarlo)?

O tal vez quiero hacer algo estúpido aquí, y realmente debería usar simplemente UCA para comparación de igualdad (cualquier muestra de código, por favor)?

+10

Cadenas iguales() hace exactamente lo que se supone que debe hacer y comparar palabras con ortografía equivalente en ciertos idiomas no es parte de eso, así que me parece que decir que falla miserablemente es engañoso. – Stefan

+0

@Stefan: El problema es que no lo es. Por ejemplo, para cadenas que contienen caracteres acentuados o diéresis (à o ä) devolverá ** falso ** si una de las cadenas usaría la descomposición canónica. La ortografía puede ser la misma, no importa. Incluso los resultados peores le darán equalalsIgnoreCase(): las variantes de casos como sharp s o sigma final no serán reconocidos. Eso es solo porque estos métodos usan una comparación binaria que no es adecuada para cadenas internacionales. –

+0

la palabra clave es descomposición canónica. Esta es una característica de lenguaje (natural) y no tiene nada que ver con la represantación de cadenas, de hecho, en la mayoría de los casos, desea que se trate de manera diferente como una cadena. Estoy de acuerdo contigo en equalsIgnoreCase en que uno es malo porque borra la línea entre una Cadena que es solo un contenedor de Caracteres y Palabras en un Idioma/Configuración regional. – Stefan

Respuesta

3

No puedo encontrar ninguna Collator para danés; se supone que el incorporado para la localidad danesa es correcto. No estoy seguro de que su suposición de que ae se debe ordenar con æ contiene, específicamente debido a ciertas palabras extranjeras (por ejemplo "aerofobi") en danés (no soy un hablante danés, aunque sí hablo sueco).

Pero, si desea ordenar juntos, parece que tienes dos maneras de hacer esto, dependiendo de qué contexto estás en En ciertos contextos, sólo la sustitución de los caracteres podría ser approprite:.

String str = "USA lover graekenland støtte"; 
String sortStr = str.replace("ae", "æ"); 

La otra opción, tal vez mejor, es la que ha especificado; usando RuleBasedCollator. Usando el ejemplo de los javadocs, esto es bastante trivial:

String danish = "< 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" + 
       "< \u00E6 = ae," +  // Latin letter ae 
       " \u00C6 = AE " +  // Latin letter AE 
       "< \u00F8, \u00D8" +  // Latin letter o & O with stroke 
       "< \u00E5 = a\u030A," + // Latin letter a with ring above 
       " \u00C5 = A\u030A;" + // Latin letter A with ring above 
       " aa, AA"; 
RuleBasedCollator danishCollator = new RuleBasedCollator(danish); 

que luego se puede utilizar:

String test1 = "USA lover Grækenland støtte"; 
String test2 = "USA lover Graekenland støtte";   // note capital 'G' 
boolean result = danishCollator.equals(test1, test2); // true 

Si usted cree que la alzadora por defecto es incorrecta, es posible que desee report a bug. (Ha habido previamente similar bugs).

Actualización: Lo comprobé con una enciclopedia impresa en idioma danés.De hecho, hay palabras que comienzan con 'ae' (principalmente palabras de idiomas extranjeros, "aeróbicos", por ejemplo) que son no clasificados con (y por lo tanto no igual a) palabra que comienza con 'æ'. Entonces, aunque veo por qué querrías tratarlos como iguales en muchas circunstancias, no son estrictamente así.

+0

No estoy preguntando sobre la clasificación. Las reglas danesas para clasificar son correctas. Para ser honesto, ni siquiera se trata de reglas danesas, solo las reglas para la comparación de igualdad. Simplemente no existen tales reglas disponibles públicamente todavía. –

+0

Derecha, y si utiliza el Clasificador con el conjunto proporcionado, su 'ae' y 'æ' son iguales. – beerbajay

0

Una forma de obtener reglas para una configuración regional específica es utilizar la función getRules. Sin embargo, en Android, esta función devuelve una cadena vacía.

RuleBasedCollator collTemp = (RuleBasedCollator) Collator 
      .getInstance(Locale.US); 
    String usRules = collTemp.getRules(); 


    //Save rules in a file 
    String rulesPath = "C:\\projects\\droid\\rules.txt"; 
    BufferedWriter out = new BufferedWriter 
      (new OutputStreamWriter(new FileOutputStream(rulesPath),"UTF-16")); 
    out.write(usRules); 
    out.close(); 

Estas reglas son las mismas que las utilizadas por la función de comparación.

if (collTemp.compare(target, str) < 0) 

Nota: Intenté tapar las reglas de mi JDK cadena aplicación de escritorio en Android RuleBasedCollator constructor, pero me da U_INVALID_FORMAT_ERROR (en Android solamente). Así que todavía estoy tratando de descubrir cómo obtener las reglas de EE. UU. En Android.

Cuestiones relacionadas