2011-12-05 25 views
15

我們都知道使用String的equals()方法進行等式比較會失敗。相反,應該使用Collator,像這樣:我在哪裏可以找到一組用於字符串平等比較的整理規則?

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

現在,此代碼的工作,那就是除非 uiLocale設置爲丹麥的結果是正確的。在這種情況下,它會產生錯誤。我當然明白爲什麼這個事情發生了:這僅僅是因爲該方法是相等這樣實現的:

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

這個方法調用,用於分類和檢查,如果字符串是相同的一個。它們不是,因爲丹麥特定的整理規則要求之後進行排序(如果我正確理解比較方法的結果)ae。然而,這些字符串是真的是相同,與此強度兩種情況下的差異和這種兼容性字符(這就是所謂的)應被視爲平等。

要解決這個問題,可以使用RuleBasedCollator以及適用於相等情況的特定規則集。
最後的問題是:CLDRchart似乎沒有人知道在哪裏可以得到這樣的特定規則(不僅是丹麥,但對其他語言),使兼容字符,連字等將作爲平等的(處理不包含這樣或我沒有搜索它)?

或者,也許我想在這裏做一些愚蠢的事,我真的應該使用簡單UCA是否相等的比較(任意代碼示例,請)?

+10

字符串equals()完全按照它應該做的事情進行,並且在某些語言中將單詞與等效拼寫進行比較不是其中的一部分,所以我發現它的失敗是令人誤解的。 – Stefan

+0

@Stefan:問題在於它不是。例如,對於包含重音字符或元音變音的字符串(à或ä),如果其中一個字符串使用規範分解,它將返回** false **。拼寫可能是一樣的,沒關係。更糟的結果會給你equalsIgnoreCase() - 例如sharp s或final sigma等案例變體將無法識別。這是因爲這些方法使用不適合國際字符串的二進制比較。 –

+0

該關鍵字是規範分解。這是一種(自然)語言功能,與String represantation無關,實際上在大多數情況下,您希望將它們作爲字符串進行區別對待。我同意你在equalsIgnoreCase中的一個不好的地方,因爲它模糊了字符串和語言/語言環境中字符的容器之間的界限。 – Stefan

回答

3

我找不到任何現有的Collat​​or for danish;丹麥語言環境的內置應用程序應該是正確的。我不確定你認爲ae應該與æ排序的假設,特別是由於丹麥語中的某些外來詞語(例如"aerofobi")(我不是丹麥語說話者,雖然我的確說瑞典語)。

但是,如果你想在一起進行排序,就好像你有兩種方法可以做到這一點,取決於你在什麼背景下在某些情況下,只需更換字符可能是approprite:

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

另一個,也許更好,選項是你指定的選項;使用RuleBasedCollator。從使用的javadoc的例子,這是非常簡單的:

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

然後你可以使用:

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 

如果您認爲默認的排序器是不正確,你不妨report a bug。 (之前已有similar bugs)。

更新:我用打印的丹麥語百科全書對此進行了檢查。確實有以'ae'開頭的詞(主要是來自外語的詞;例如,「有氧運動」),它們是而不是排序(因此不等於)以'æ'開頭的詞。所以,儘管我明白了爲什麼你們想在很多情況下把它們看作是平等的,但它們並不嚴格。

+0

我不是在問排序。丹麥的排序規則是正確的。說實話,它甚至不涉及丹麥規則,只是平等比較的規則。目前根本沒有這樣的公開可用的規則。 –

+0

對,如果你使用Collat​​or和提供的集合,你的'ae'和'æ'是相等的。 – beerbajay

0

獲取特定區域設置規則的一種方法是使用getRules函數。但是,在Android中,這個函數返回一個空字符串。

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

這些規則與比較函數使用的規則相同。

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

注:我想從我的JDK桌面應用串入的Android RuleBasedCollat​​or構造堵塞規則,但我(僅在Android設備)獲得U_INVALID_FORMAT_ERROR。所以我仍然試圖找出如何在Android中獲得美國規則。

相關問題