2015-06-09 22 views
9

我想將英語(i)的「I」的小寫字母與土耳其語(i)的「İ」的小寫字母相匹配。它們是相同的字形,但它們不匹配。當我做System.out.println("İ".toLowerCase());字符我和一個點被打印(這個網站不正確顯示它)如何在java中與土耳其語「我」相匹配?

有沒有一種方法來匹配那些?(最好沒有硬編碼它)我想使程序匹配相同與語言和utf代碼無關的字形。這可能嗎?

我測試了標準化沒有成功。

public static void main(String... a) { 
    String iTurkish = "\u0130";//"İ"; 
    String iEnglish = "I"; 
    prin(iTurkish); 
    prin(iEnglish); 
} 

private static void prin(String s) { 
    System.out.print(s); 
    System.out.print(" - Normalized : " + Normalizer.normalize(s, Normalizer.Form.NFD)); 
    System.out.print(" - lower case: " + s.toLowerCase()); 
    System.out.print(" - Lower case Normalized : " + Normalizer.normalize(s.toLowerCase(), Normalizer.Form.NFD)); 
    System.out.println(); 

} 

結果不正確的網站顯示,但第一線(iTurkish)仍具有̇附近小寫我。

目的和問題

這將是一個多語言字典。我希望程序能夠識別「İFEL」以「if」開頭。爲了確保它們不區分大小寫,我首先將兩個文本都轉換爲小寫。 İFEL變成我(點)惡魔和「如果」不被識別爲它的一部分

+2

兩個字母是不一樣的UNI代碼,以便它們不匹配。 – Zelldon

+1

可以使用[commons-lang](https://commons.apache.org/proper/commons-lang/)從字符串中去除變音符號:org.apache.commons.lang3.StringUtils.stripAccents(String) – agad

+0

@agad Wouldn它阻止我從我的分化?我會考慮,如果沒有辦法做到這一點。 – WVrock

回答

9

如果你打印出你所看到的字符的十六進制值,所不同的是明確的:

İ 0x130 - Normalized : İ 0x49 0x307 - Lower case: i̇ 0x69 0x307 - Lower case Normalized : i̇ 0x69 0x307 
I 0x49 - Normalized : I 0x49 - Lower case: i 0x69 - Lower case Normalized : i 0x69 

正常化土耳其語İ不會爲您提供英語I,相反,它會爲您提供英語I,後跟一個變音符號,0x307。這是正確的,並且是正常化過程所期待的。規範化不是「轉換爲ASCII」操作。正如Normalizer的文檔中提到的那樣,它所遵循的過程是一個非常嚴格定義的標準,即Unicode Standard Annex #15 — Unicode Normalization Forms

numerous ways to strip diacritics,無論是之前或之後正常化。你需要什麼取決於你的使用情況的細節,但爲您的使用情況下,我會建議使用GuavaCharMatcher類正火後剝離非ASCII字符,如:

String asciiString = CharMatcher.ASCII.retainFrom(normalizedString); 

This answer去深入瞭解\p{InCombiningDiacriticalMarks}的作用,以及它爲什麼不理想。我的CharMatcher解決方案也不理想(鏈接答案提供了更強大的解決方案),但爲了快速解決問題,您可能會發現僅保留ASCII字符「足夠好」。這比基於Pattern的方法更接近「正確」並且更快。

+1

+1,有趣的副作用'「İ」.toLowerCase()似乎決定它需要分解字符。至少在這裏...... – dhke

+0

每個人似乎都建議剝離變音符號。我可能會這樣做。我想匹配「ıf」與「İF」比不匹配「İF」與「İF」更好。艱難我不確定這是否會如此。 – WVrock

+1

@WVrock - 正如您所介紹的那樣,解決您問題的最佳解決方案是去除變音符號。您可能有其他要求,但您沒有告訴我們哪些可能需要不同的解決方案。但廣義而言,如果您希望某人能夠輸入英文字符並將其映射到土耳其字符,您將不得不去除*一些*信息,並且您將很難避免誤報和漏報。你的解決方案應該儘量減少對你的用例更糟糕的地方。 – dimo414

-1

您可以使用波紋管代碼:

public static void main(String... a) { 

     String iTurkish = "\u0130";//"İ"; 
     String iEnglish = "I"; 
     prin(iTurkish); 
     prin(iEnglish); 


} 

private static void prin(String s) { 
    System.out.print(s); 
    String nfdNormalizedString = Normalizer.normalize(s, Normalizer.Form.NFD); 
    Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); 
    System.out.print(" - Normalized : " + pattern.matcher(nfdNormalizedString).replaceAll("")); 
    System.out.print(" - lower case: " + s.toLowerCase()); 
    System.out.print(" - Lower case Normalized : " + Normalizer.normalize(pattern.matcher(nfdNormalizedString).replaceAll("").toLowerCase(), Normalizer.Form.NFD)); 
    System.out.println(); 

} 

還是看Converting Symbols, Accent Letters to English Alphabet

+0

從Utils類複製代碼並將其作爲自己呈現在此處並不很好。 – agad

+0

爲什麼不投票?我提供了鏈接「http://stackoverflow.com/questions/1008802/converting- symbols-accent-letters-to-english-alphabet」。沒有看到它嗎? 「agad」 – Rafiq

+0

+1用於提供指向答案的鏈接並使其適應給定的代碼。儘管如果你首先提供了鏈接,然後澄清你正在使用別人的代碼會更好。 – WVrock