2013-06-05 20 views
10

Mam listę słów w języku arabskim, które chciałabym posortować. Próbowałem standardowy Collator z różnymi lokacjami (jak angielski lub francuski, ale bez większej nadziei), a nawet stworzyłem własny RuleBasedCollator, ale bezskutecznie. Wygląda na to, że domyślne sortowanie zależy od kolejności wartości Unicode, która w wielu przypadkach działa, ale najwyraźniej nie w tym.Sortowanie arabskich słów w Javie

Postępując zgodnie z instrukcjami javadocs, RuleBasedCollator wymaga ciągu znaków określającego znaki w kolejności, w jakiej mają być posortowane. I stworzył następujący ciąg Biorąc unicode kody z this table:

String arabicLetters = "< \u0623=\uFE83=\uFE84 < \u0628=\uFE8F=\uFE90=\uFE92=\uFE91 < \u062A=\uFE95=\uFE96=\uFE98=\uFE97 < \u062B=\uFE99=\uFE9A=\uFE9C=\uFE9B < \u062C=\uFE9D=\uFE9E=\uFEA0=\uFE9F < \u062D=\uFEA1=\uFEA2=\uFEA4=\uFEA3 < \u062E=\uFEA5=\uFEA6=\uFEA8=\uFEA7 < \u062F=\uFEA9=\uFEAA < \u0630=\uFEAB=\uFEAC < \u0631=\uFEAD=\uFEAE < \u0632=\uFEAF=\uFEB0 < \u0633=\uFEB1=\uFEB2=\uFEB4=\uFEB3 < \u0634=\uFEB5=\uFEB6=\uFEB8=\uFEB7 < \u0635=\uFEB9=\uFEBA=\uFEBC=\uFEBB < \u0636=\uFEBD=\uFEBE=\uFEC0=\uFEBF < \u0637=\uFEC1=\uFEC2=\uFEC4=\uFEC3 < \u0638=\uFEC5=\uFEC6=\uFEC8=\uFEC7 < \u0639=\uFEC9=\uFECA=\uFECC=\uFECB < \u063A=\uFECD=\uFECE=\uFED0=\uFECF < \u0641=\uFED1=\uFED2=\uFED4=\uFED3 < \u0642=\uFED5=\uFED6=\uFED8=\uFED7 < \u0643=\uFED9=\uFEDA=\uFEDC=\uFEDB < \u0644=\uFEDD=\uFEDE=\uFED0=\uFEDF < \u0645=\uFEE1=\uFEE2=\uFEE4=\uFEE3 < \u0646=\uFEE5=\uFEE6=\uFEE8=\uFEE7 < \u0647=\uFEE9=\uFEEA=\uFEEC=\uFEEB < \u0648=\uFEED=\uFEEE < \u064A=\uFEF1=\uFEF2=\uFEF4=\uFEF3 < \u0622=\uFE81=\uFE82 < \u0629=\uFE93=\uFE94 < \u0649=\uFEEF=\uFEF0 < \u0627"; 

Te arabskie litery mogą wziąć cztery formy w zależności od miejsca, w którym są one w słowie. Dlatego to, co zrobiłem w powyższym łańcuchu reguł, czyni równe wszystkie 4 formy każdej litery. Następnie wskazuję kolejność liter oddzielających je od "<". Wyobrażam sobie, że jest to właściwy sposób.

Teraz, gdy mam kolekcję o dniach tygodnia (klasyfikowane w tym przypadku dzień tygodnia, a nie „alfabetycznie”):

الأَحَد, الاِثنَين, الثُّلاثاء, الأَربِعاء, الخَميس, الجُمعة,السَّبت 

Wyniki Dostaję nie są klasyfikowane w wszystkie:

الأَحَد, الخَميس, الاِثنَين, الثُّلاثاء, الأَربِعاء, السَّبت, الجُمعة 

Poza tym, dla tak małej ilości słów zajmuje dużo czasu, przez co nie nadaje się do użytku.

Czy ktoś wie, czy robię coś złego, czy też istnieje biblioteka ratunkowa, która już to obsługuje?

Zrobiłem kilka google przed napisaniem tego i jestem zaskoczony, że nie znalazłem ani jednego wyniku.

Dzięki!


UPDATE z kodem:

public static class TranslatableComparator implements java.util.Comparator<Translatable> { 
     @Override 
     public int compare(Translatable t1, Translatable t2) { 

      String sortingRules = "< \u0623=\uFE83=\uFE84 < \u0628=\uFE8F=\uFE90=\uFE92=\uFE91 < \u062A=\uFE95=\uFE96=\uFE98=\uFE97 < \u062B=\uFE99=\uFE9A=\uFE9C=\uFE9B < \u062C=\uFE9D=\uFE9E=\uFEA0=\uFE9F < \u062D=\uFEA1=\uFEA2=\uFEA4=\uFEA3 < \u062E=\uFEA5=\uFEA6=\uFEA8=\uFEA7 < \u062F=\uFEA9=\uFEAA < \u0630=\uFEAB=\uFEAC < \u0631=\uFEAD=\uFEAE < \u0632=\uFEAF=\uFEB0 < \u0633=\uFEB1=\uFEB2=\uFEB4=\uFEB3 < \u0634=\uFEB5=\uFEB6=\uFEB8=\uFEB7 < \u0635=\uFEB9=\uFEBA=\uFEBC=\uFEBB < \u0636=\uFEBD=\uFEBE=\uFEC0=\uFEBF < \u0637=\uFEC1=\uFEC2=\uFEC4=\uFEC3 < \u0638=\uFEC5=\uFEC6=\uFEC8=\uFEC7 < \u0639=\uFEC9=\uFECA=\uFECC=\uFECB < \u063A=\uFECD=\uFECE=\uFED0=\uFECF < \u0641=\uFED1=\uFED2=\uFED4=\uFED3 < \u0642=\uFED5=\uFED6=\uFED8=\uFED7 < \u0643=\uFED9=\uFEDA=\uFEDC=\uFEDB < \u0644=\uFEDD=\uFEDE=\uFED0=\uFEDF < \u0645=\uFEE1=\uFEE2=\uFEE4=\uFEE3 < \u0646=\uFEE5=\uFEE6=\uFEE8=\uFEE7 < \u0647=\uFEE9=\uFEEA=\uFEEC=\uFEEB < \u0648=\uFEED=\uFEEE < \u064A=\uFEF1=\uFEF2=\uFEF4=\uFEF3 < \u0622=\uFE81=\uFE82 < \u0629=\uFE93=\uFE94 < \u0649=\uFEEF=\uFEF0 < \u0627"; 
      RuleBasedCollator col = null; 
      try { 
       col = new RuleBasedCollator(sortingRules); 
      } catch (ParseException e) { 
       //col = (RuleBasedCollator)RuleBasedCollator.getInstance(Locale.FRENCH); 
      } 

      return col.getCollationKey(t1.getTranslation().getText()).compareTo(col.getCollationKey(t2.getTranslation().getText())); 
     } 
    } 
+1

Możesz pisać trochę więcej kodu proszę? tylko po to, żeby zobaczyć, co się właściwie dzieje? – shaunvxc

+0

@shaunvxc zaktualizowano kodem. – Gonan

+0

Nie jestem w pełni obeznany z RuleBasedCollator, ale co się stanie, gdy oddzielisz znaki, których wartość ma być równa przecinkom? Coś takiego: " shaunvxc

Odpowiedz

5

Nie trzeba zdefiniować własny Collator, wystarczy użyć wbudowanego w jednym dla arabskiego. Twój Comparator wtedy wygląda to

public int compare(Translatable t1, Translatable t2) { 
     Collator.getInstance(new Locale("ar")).compare(t1.getTranslation().getText(), t2.getTranslation().getText()); 
} 

(można sprawdzić, czy Zbieraczka jest dostępna dla arabskiego, przeglądając wyniki z Collator.getAvailableLocales().)

Jak zauważył w komentarzach, jeśli martwisz się o wydajności ty należy obliczyć klucze sortowania, przechowywać je w swoich obiektach Translatable i sortować je w zamian.

Jeśli naprawdę chcesz zobaczyć, gdzie różnice są między tym, co określono a średnia Zbieraczka, po prostu wydrukować zasady:

System.out.println((RuleBasedCollator) Collator.getInstance(new Locale("ar"))).getRules(); 
+0

Naprawiłem to. Robiłem coś niewłaściwego gdzie indziej w kodzie. Zasadniczo modyfikowałem listę przed sortowaniem za pomocą tej metody, dlatego otrzymałem złe wyniki. Jak wspomina rxg, nie ma potrzeby używania do tego specjalnego Collatora. Sortowanie będzie działać, przyjmując wartości znaków Unicode, a ponieważ są one uporządkowane alfabetycznie, to wszystko. O występie, w rzeczywistości nie zauważyłem, że tworzyłem obiekt do każdego porównania. Zmieniłem go na to, co sugerował superEB, a teraz zajmuje to mniej niż sekundę. Dzięki! – Gonan

+0

Ponieważ to właśnie robiłem przed wypróbowaniem podejścia RuleBasedCollator i zasadniczo dlatego, że jest to sposób, aby to zrobić, zaznaczę to jako odpowiedź. – Gonan