2011-12-05 6 views
15

Sappiamo tutti che l'utilizzo del metodo equals() di String per il confronto di uguaglianza fallirà miseramente. Invece, si dovrebbe usare Collator, in questo modo:Dove posso trovare una serie specifica di regole di confronto per il confronto delle uguaglianze delle stringhe?

// 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); 

Ora, questo codice funziona, che è risultato è vero meno uiLocale è impostato a Danese. In tal caso produrrà false. Certamente capisco perché questo è accaduto: questo è solo perché il metodo è uguale è implementato in questo modo:

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

Questo metodo chiama quello che viene utilizzato per l'ordinamento e verificare se le stringhe sono uguali. Non lo sono, poiché le regole di confronto specifiche danesi richiedono che lo æ venga ordinato dopo (se comprendo correttamente il risultato del metodo di confronto) ae. Tuttavia, queste stringhe sono davvero uguali, con questa forza sia le differenze tra i casi che i caratteri di compatibilità (che è ciò che viene chiamato) dovrebbero essere considerati uguali.

Per risolvere questo problema, è necessario utilizzare RuleBasedCollator con un set specifico di regole che funzionerà per il caso di uguaglianza.
Infine la domanda è: qualcuno sa dove posso ottenere regole così specifiche (non solo per il danese, ma anche per altre lingue), in modo che i caratteri di compatibilità, le legature, ecc. Siano trattati allo stesso modo (CLDRchart non sembra per contenere tale o non sono riuscito a cercarlo)?

O forse voglio fare qualcosa di stupido qui, e dovrei davvero usare semplicemente UCA per il confronto di uguaglianza (qualsiasi esempio di codice, per favore)?

+10

Stringhe equivalenti() fa esattamente ciò che si suppone stia facendo e paragonando le parole con lo spelling equivalente in alcune lingue non fa parte di questo, quindi trovo che dire che fallisce miseramente è fuorviante. – Stefan

+0

@Stefan: il problema è che non lo è. Ad esempio, per le stringhe contenenti caratteri accentati o dieresi (o o) verrà restituito ** falso ** se una delle stringhe userebbe la decomposizione canonica. L'ortografia potrebbe essere la stessa, non importa. Risultati ancora peggiori ti daranno equalsIgnoreCase() - le varianti di caso come sharp s o finale sigma non saranno riconosciute. Questo perché questi metodi usano il confronto binario che non è adatto per le stringhe internazionali. –

+0

la parola chiave è una decomposizione canonica. Questa è una caratteristica del linguaggio (naturale) e non ha nulla a che fare con la rappresentazione di String, in realtà nella maggior parte dei casi si desidera che vengano trattati diversamente come String. Sono d'accordo con te su equalsIgnoreCase che uno è cattivo perché sfoca la linea tra una stringa che è solo un contenitore per caratteri e parole in una lingua/locale. – Stefan

risposta

3

Non riesco a trovare alcun Collator esistente per danese; il built-in per il locale danese dovrebbe essere corretto. Non sono sicuro che la tua ipotesi di ordinare ae con æ, in particolare a causa di alcune parole straniere (ad esempio "aerofobi") in danese (non sono un oratore danese, anche se parlo svedese).

Ma, se si desidera ordinare loro insieme, sembra che ci sono due modi per farlo, a seconda di quale contesto si è in In certi contesti, semplicemente sostituendo i caratteri potrebbe essere approprite:.

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

L'altra opzione, forse migliore, è quella specificata; utilizzando RuleBasedCollator. Utilizzando l'esempio dai javadocs, questo è abbastanza banale:

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); 

che è quindi possibile utilizzare:

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 

Se credi che il fascicolatore predefinito non è corretto, si potrebbe desiderare di report a bug. (Ci sono stati in precedenza similar bugs).

Aggiornamento: L'ho verificato con un'enciclopedia in lingua danese stampata.Esistono in effetti parole che iniziano con "ae" (principalmente parole da lingue straniere, "aerobica", ad esempio) che sono non ordinate con (e quindi non uguale a) parole che iniziano con "æ". Quindi, anche se vedo perché vorresti trattarli come uguali in molte circostanze, non lo sono rigorosamente.

+0

Non sto chiedendo di ordinare. Le regole danesi per lo smistamento sono corrette. Ad essere onesti non si tratta nemmeno delle regole danesi, ma solo delle regole per il confronto delle uguaglianze. Semplicemente non esistono ancora tali regole pubblicamente disponibili. –

+0

Esatto, e se si utilizza il Collator con il set fornito, i valori 'ae' e 'æ' sono uguali. – beerbajay

0

Un modo per ottenere regole per un locale specifico è utilizzare la funzione getRules. Tuttavia, in Android, questa funzione restituisce una stringa vuota.

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(); 

Queste regole sono le stesse utilizzate dalla funzione di confronto.

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

Nota: ho cercato di colmare le regole del mio JDK stringa di un'applicazione desktop in costruttore RuleBasedCollator Android, ma ho U_INVALID_FORMAT_ERROR (in solo Android). Quindi sto ancora cercando di capire come ottenere le regole americane in Android.