2015-06-09 8 views
9

Chcę dopasować małą literę "I" języka angielskiego (i) do małej litery "İ" języka tureckiego (i). Są one tym samym glifem, ale nie pasują do siebie. Kiedy robię System.out.println("İ".toLowerCase());, drukowany jest znak i oraz kropka (strona ta nie wyświetla się poprawnie)Jak dopasować "i" do tureckiego w java?

Czy istnieje sposób na ich dopasowanie? (Najlepiej bez twardego kodowania) Chcę, aby program pasował do tego samego glify niezwiązane z językiem i kodem utf. czy to możliwe?

Testowałem normalizację bez powodzenia.

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

} 

Wynik nie jest właściwie pokazano na miejscu, ale pierwsza linia (iTurkish) nadal ma ̇ pobliżu małej litery i.

Cel i problem

To będzie multi słownik językowy. Chcę, aby program mógł rozpoznać, że "İFEL" zaczyna się od "if". Aby upewnić się, że nie są one wrażliwe na wielkość liter, najpierw konwertuję oba teksty na małe litery. İFEL staje I (dot) Fel i „jeśli” nie jest rozpoznawana jako jego części

+2

Obie litery nie są takie same kod uni więc nie pasuje. – Zelldon

+1

Możesz usunąć znaki diakrytyczne z ciągu znaków za pomocą [commons-lang] (https://commons.apache.org/proper/commons-lang/): org.apache.commons.lang3.StringUtils.stripAccents (String) – agad

+0

@agad Wouldn to zapobiega różnicowaniu się od ı? Rozważałbym to, jeśli nie ma sposobu, aby to zrobić. – WVrock

Odpowiedz

9

Jeśli wydrukować wartości hex bohaterów widzisz, różnica jest oczywista:

İ 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 

Normalizowanie języka tureckiego İ nie daje angielskiego I, zamiast tego daje angielski I, po którym następuje znak diakrytyczny, 0x307. Jest to poprawne i można się spodziewać w procesie normalizacji. Normalizacja nie jest operacją "Konwertuj na ASCII". Jak wspomina dokumentacja dla Normalizer, proces, który stosuje, jest bardzo rygorystycznie zdefiniowanym standardem, czyli.

Istnieje numerous ways to strip diacritics, przed lub po normalizacji. Co trzeba będzie zależeć od specyfiki przypadku użycia, ale dla przypadku użycia Sugerowałbym użyciu Guava „s CharMatcher klasy rozebrać znaków spoza ASCII po normalizacji, np:

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

This answer idzie bardziej szczegółowo o tym, co robi \p{InCombiningDiacriticalMarks} i dlaczego nie jest idealny. Moje rozwiązanie CharMatcher też nie jest idealne (połączona odpowiedź oferuje bardziej niezawodne rozwiązania), ale dla szybkiej naprawy może się okazać, że zachowujesz tylko znaki ASCII "wystarczająco dobre". Jest to bliższe "poprawne" i szybsze niż podejście oparte na Pattern.

+1

+1, Interesujący efekt uboczny '" İ ".toLowerCase()' zdaje się decydować, że potrzebuje dekompozycji postaci. Przynajmniej tutaj ... – dhke

+0

Wszyscy zdają się sugerować usuwanie diakrytów. Prawdopodobnie zrobię to w ten sposób. Przypuszczam, że dopasowanie "ıf" z "İF" jest lepsze niż nie dopasowanie "if" z "İF". Trudno nie jestem pewien, czy tak się stanie. – WVrock

+1

@WVrock - tak jak go przedstawiłeś, najlepszym rozwiązaniem twojego problemu jest usunięcie znaków diakrytycznych. Możliwe, że masz dodatkowe wymagania, o których nam nie powiedziałeś, a które mogą zasługiwać na inne rozwiązanie. Ale ogólnie rzecz ujmując, jeśli chcesz, aby ktoś mógł pisać angielskie znaki i mapować je na tureckie, będziesz musiał usunąć * niektóre * informacje, a będziesz musiał unikać fałszywych trafień i fałszywych negatywów . Twoje rozwiązanie powinno starać się zminimalizować to, co jest gorsze w twoim przypadku użycia. – dimo414

-1

Można użyć kodu poniżej:

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

} 

Albo zobaczyć Converting Symbols, Accent Letters to English Alphabet

+0

Niezbyt przyjemnie kopiować kod z klasy Utils i prezentować tutaj jako własny. – agad

+0

Dlaczego nie głosować? Podałem link "http://stackoverflow.com/questions/1008802/converting- symbols-accent- letters- to-english-alphabet". Nie widziałem tego? "agad" – Rafiq

+0

+1 za podanie linku do odpowiedzi i dostosowanie go do podanego kodu. Chociaż byłoby lepiej, gdybyś najpierw podał link, a następnie wyjaśnił, że używasz cudzego kodu. – WVrock

Powiązane problemy