Forum Coders' city Strona Główna Coders' city
Nasza pasja to programowanie!
 

 PomocPomoc   SzukajSzukaj   UżytkownicyUżytkownicy   GrupyGrupy  RejestracjaRejestracja 
Archiwum starego forum + teoria    RSS & Panel/SideBar
 ProfilProfil   Zaloguj się, by sprawdzić wiadomościZaloguj się, by sprawdzić wiadomości   ZalogujZaloguj 

Potrzebuję szybkiej odpowiedzi na moje pytanie... Zasady

[C++] Sprawdzenie, czy w stringu zakodowanym w UTF-8 znajdują się arabskie znaki



 
Odpowiedz do tematu    Forum Coders' city Strona Główna -> C i C++
Zobacz poprzedni temat :: Zobacz następny temat  
Autor Wiadomość
Luke



Dołączył: 17 Cze 2007
Posty: 1893
Skąd: Szczecin

PostWysłany: Wto Sie 02, 2016 5:18 pm  OP    Temat postu: [C++] Sprawdzenie, czy w stringu zakodowanym w UTF-8 znajdują się arabskie znaki Odpowiedz z cytatem Pisownia

Dostając na wejściu std::string chciałbym sprawdzić, czy wewnątrz znajdują się znaki z alfabetu arabskiego. Ciąg jest zakodowany w UTF-8.
Jak zrobić to w jak najbardziej bezbolesny sposób?

Mam do dyspozycji dość przestarzały kompilator C++, bez wsparcia dla C++11 i nowszych standardów (dokładnie jest to: Microsoft (R) C/C++ Optimizing Compiler Version 15.01.50304.03 for ARM).

_________________
Moje projekty | Tani hosting
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora
nowator



Dołączył: 16 Sty 2010
Posty: 214
Skąd: Częstochowa

PostWysłany: Sro Sie 03, 2016 4:56 pm      Temat postu: Odpowiedz z cytatem Pisownia

Ja bym posłużył się oto tą listą znaków. I sprawdziłbym po kolei czy każdy znak znajduje się w odpowiednim zakresie.
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora Numer GG
marcin_an



Dołączył: 26 Maj 2005
Posty: 18822

PostWysłany: Sro Sie 03, 2016 6:42 pm      Temat postu: Odpowiedz z cytatem Pisownia

nowator:
Wcześniej ręcznie pisząc [błędnie działający] dekoder UTF-8? ;)

Do tego "ta lista" jest błędna: w Unicode skrypt arabski występuje w 7 blokach, nie tylko U+0600-U+06FF, i nie wszystkie znaki w U+0600-U+06FF należą do skryptu arabskiego (np. U+0605). Jakby tego było mało, w części przypadków o klasyfikacji będą decydowały inne znaki (np. w przypadku U+064B: ًo - w tym przypadku skyptem jest Latn, nie Arab).

Luke:
Witamy w rzeczywistości C++, w którym w roku 2016 społeczność nadal nie zdecydowała się, jak trzymać ciągi znaków*, nie mówiąc już o zbudowaniu czegokolwiek do ich przetwarzania.

Niestety, muszę cię zmartwić: w obecnym stanie języka w C++ nie zrobisz tego w żaden sensowny sposób.

Najprostszą i najpewniejszą metodą jest przekonwertowanie tego ciągu na QString z Qt, który używa kodowania UTF-16. Następnie przebiegasz po każdym QChar i, jeżeli jest to kompletny znak (QChar::isSurrogate zwraca false), pobierasz skrypt QChar::script. Znaki mające skrypt QChar::Script_Arabic na pewno należą do skryptu arabskiego. Jeżeli otrzymasz QChar::Script_Inherited, musisz sprawdzić skrypt ostatniego znaku, który miał skrypt inny niż QChar::Script_Inherited - i jego użyć. W przypadku gdy QChar::isSurrogate zwraca true, musisz przeliczyć parę na pojedynczy 21-bitowy kod znaku i sprawdzić - analogicznie jak wcześniej - tylko że metodą QChar::script(uint). Zwróć przy tym uwagę na to, że QChar nie potrafi rozróżnić lower-surrogate of upper-surrogate, więc podczas konwersji musisz się upewnić, że masz prawidłowe wartości.

Innym rozwiązaniem (napisałeś o archaicznym kompilatorze i nie wiadomo, jaka platforma, więc Qt może nie działać) jest użycie ICU. icu::UnicodeString::fromUtf8 konwertuje z UTF-8 na UTF-16. Dalej idzie tak samo, jak w Qt, tylko że z odpowiednio innymi funkcjami - U16_IS_SURROGATE_LEAD, uscript_getScript - i wartościami z enumeracji UScriptCode.

Jeśli nie odstrasza cię użycie Glib, powyższe można na niego przełożyć: g_utf8_to_ucs4, g_unichar_get_script i GUnicodeScript. Jest to również najprostsze rozwiązanie, bo operuje się na UTF-32, więc kodowanie jest zawsze stałej długości i odpadają kody z low/high-surrogate.

Czwartą opcją jest użycie współczesnego języka (np. Javy, Pythona, ...) i oddelegowanie tego zadania do nich. Java udostępnia Character.isLowSurrogate oraz Character.UnicodeScript.of (nadal niestety musisz ręcznie dekodować UTF-16, ale reszta jest załatwiona). Python to nie moja działka, ale widziałem gotowe biblioteki robiące to w analogiczny sposób (tylko musisz uważać na to, że Python może być skompilowany tak w wersji UTF-16, jak i UTF-32**).

Piąta możliwość: użycie PCRE i wyrażeń regularnych ze wzorcem (*UTF8)\p{Arabic}. Wady: API tej biblioteki jest mocno upierdliwe, dokumentacja nędzna, a przede wszytkim musisz być w stanie ją swoim kompilatorem zbudować, i to z włączoną obsługą UTF-8.

Jeżeli masz pewność, że lokalizacja na platformie docelowej używa kodowania UTF-8 oraz wchar_t używa UTF-16 lub UTF-32 (i masz pewność, że to nigdy się nie zmieni, a twoja aplikacja nie będzie używana w innej sytuacji), możesz użyć ::std::ctype::widen z nagłówka locale lub, w ostateczności, ::std::mbrtowc z cwchar. Następnie musisz zaimplementować sprawdzanie, czy kod to low/high-surrogate, konwertować na właściwy 21-bitowy kod, ręcznie przeparsować Scripts.txt i na jego podstawie decydować, do jakiego skryptu należy znak. Po zrobieniu tego postępuj zgodnie z algorytmem wskazanym we wcześniejszych paragrafach. Gorąco odradzam takie rozwiązanie. Jeśli jednak tego użyjesz, odbiorca/użytkownik aplikacji musi zostać wyraźnie ostrzeżony o wymogach dotyczących cech platformy, na której aplikacja może być uruchamiana.

Jeśli wszystko powyższe zawiedzie, pozostaje to, co zaproponował przedmówca: samodzielna implementacja konwersji z UTF-8 na UTF-32, a następnie postępowanie jak w paragrafie wyżej. Tego już nawet nie odradzam, bo to za słabe słowo. Nie odważyłbym się też używać w ten sposób napisanej aplikacji.
____
* Teoretycznie istnieje ::std::basic_string i jego konkretyzacje, ale w praktyce każdy projekt ich unika i wymyśla sobie od nowa swoje własne rozwiązania, przy okazji tylko powielając błędy poprzedników.
** Opcja --enable-unicode z wartością odpowiednio ucs2 lub ucs4. Z tym, że nie musisz tego sprawdzać w kodzie: po prostu bądź świadom tego, że możesz równie dobrze otrzymać low/high-surrogate, jak i wartości ponad U+FFFF.
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość
Luke



Dołączył: 17 Cze 2007
Posty: 1893
Skąd: Szczecin

PostWysłany: Pią Sie 19, 2016 8:46 am  OP    Temat postu: Odpowiedz z cytatem Pisownia

Dzięki za rozbudowaną odpowiedź. :)

BTW. Qt działa z tym kompilatorem.

_________________
Moje projekty | Tani hosting
Powrót do góry
Zobacz profil autora Wyślij prywatną wiadomość Odwiedź stronę autora
Wyświetl posty z ostatnich:   
Odpowiedz do tematu    Forum Coders' city Strona Główna -> C i C++ Wszystkie czasy w strefie CET (Europa)

Strona 1 z 1

 
Skocz do:  
Możesz pisać nowe tematy
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Możesz dodawać załączniki na tym forum
Możesz pobierać pliki z tego forum




Debug: strone wygenerowano w 0.24765 sekund, zapytan = 11
contact

| Darmowe programy i porady Jelcyna | Tansze zakupy w Helionie | MS Office Blog |