2012-10-26 7 views
10

Próbuję zaimplementować obsługę tekstów w systemie Windows z zamiarem przeniesienia na platformę Linux. Idealnym rozwiązaniem byłoby wspieranie języków międzynarodowych w jednolity sposób, ale wydaje się, że nie jest to łatwe do zrealizowania przy rozpatrywaniu dwóch wspomnianych platform. Spędziłem dużo czasu czytając UNICODE, UTF-8 (i inne kodowania), widechary i takie i oto, co do tej pory zrozumiałem:UNICODE, UTF-8 i Windows Mess

UNICODE, jako standard, opisuje zestaw znaków, które można mapować i kolejności, w jakiej występują. Odnoszę się do tego jako "co": UNICODE określa , co będzie dostępne pod adresem.

UTF-8 (i inne kodowania) określ jak: Jak każda postać będzie reprezentowana w formacie binarnym.

Teraz, w systemie Windows, początkowo zdecydowali się na kodowanie UCS-2, ale to nie spełniło wymagań, więc UTF-16 to to, co mają, a także, w razie potrzeby, wiele znaków.

Więc tutaj jest delemma:

  1. Okna wewnętrznie tylko robi UTF-16, więc jeśli chcesz obsługiwać znaki międzynarodowe jesteś zmuszony do przejścia na ich widechar wersjach używać OS nazywa się odpowiednio. Wydaje się, że nie ma żadnego wsparcia dla wywoływania czegoś takiego jak CreateFileA() z wielobajtowym ciągiem znaków UTF-8 i sprawiają, że wygląda on prawidłowo. Czy to jest poprawne?
  2. W języku C istnieją niektóre wielobajtowe funkcje wspierające (_mbscat, _mbscpy, itp.), Jednak w oknach typ znaku jest zdefiniowany jako unsigned char * dla tych funkcji. Biorąc pod uwagę, że seria funkcji mbs nie jest kompletnym zbiorem (tzn. Nie ma _bbstol do konwertowania wielobajtowych łańcuchów na długie, na przykład), jesteś zmuszony do korzystania z niektórych wersji char * wersji funkcji uruchomieniowych, co prowadzi do problemów z kompilatorem z powodu podpisanej/niepodpisanej różnicy między tymi funkcjami. Czy ktoś nawet z nich korzysta? Czy po prostu robisz duży stos rzucania, aby obejść błędy?
  3. W C++, std :: string zawiera iteratory, ale są one oparte na char_type, a nie na punktach kodu. Więc jeśli zrobię ++ na std :: string :: iterator, otrzymam następny char_type, a nie następny punkt kodowy. Podobnie, jeśli wywołasz std :: string :: operator [], otrzymasz odwołanie do char_type, który ma wielki potencjał, aby nie być kompletnym punktem kodowym. Więc w jaki sposób jeden iterować std :: string według punktu kodowego? (C ma funkcję _mbsinc()).
+1

Nie "wielobajtowe w razie potrzeby". To po prostu "wielobajtowe". Nie wiesz, czy jest to "konieczne", dopóki nie zaczniesz go przetwarzać. –

+0

Oto mój [post of mine] (http://stackoverflow.com/questions/6300804/wchars-encodings-standards-and -portability) na ten temat; może cię to interesuje. Dla (3) skonwertuj dane do UTF-32 (idealnie przechowywane w 'char32_t'), a następnie kod wskazuje równe elementy ciągów. –

+3

Należy pamiętać, że istnieje kilka uzasadnionych powodów do iteracji ciągu znaków Unicode za pomocą punktów kodowych, ponieważ grafem może być reprezentowany przez wiele punktów kodowych (z których każdy może zawierać wiele jednostek kodu w UTF-8 lub UTF-16, ale w przypadku wiele praktycznych celów to ten sam problem dwa razy). Normalizacja to jeden uzasadniony powód, kodowanie do UTF-8 jest kolejnym, ale są to rzeczy, do których i tak możesz użyć biblioteki. –

Odpowiedz

6
  1. Prawidłowo. Przekonwertujesz kodowanie UTF-8 do UTF-16 dla wywołań Windows API.

  2. Większość czasu będziesz używać zwykłych funkcji ciągów dla UTF-8 - strlen, strcpy (ICK), snprintf, strtol. Będą działać poprawnie ze znakami UTF-8. Albo użyj char * dla UTF-8, albo będziesz musiał rzucić wszystko.

    Należy zauważyć, że wersje podkreślenia, takie jak _mbstowcs, nie są standardem, zwykle są nazywane bez podkreślenia, na przykład mbstowcs.

  3. Trudno wymyślić przykłady, w których faktycznie chcesz użyć operator[] na ciąg Unicode, moja rada to trzymać z dala od tego. Podobnie iteracji po sznurku ma zaskakująco kilka zastosowań:

    • Jeśli parsowania ciąg (np ciąg jest C lub kod JavaScript, może chcesz składni hilighting), a następnie można zrobić większość bajt pracy -by-byte i ignoruj ​​aspekt wielobajtowy.

    • Jeśli robisz wyszukiwania, można również zrobić to bajt po bajcie (ale należy pamiętać, aby znormalizować pierwszy).

    • Jeśli szukasz przerw na słowo lub granic grapemu klastra, będziesz chciał użyć biblioteki takiej jak ICU. Algorytm nie jest prosty.

    • Wreszcie, zawsze możesz przekonwertować fragment tekstu na UTF-32 i pracować z nim w ten sposób. Myślę, że jest to najtańsza opcja, jeśli implementujesz dowolny algorytm Unicode, taki jak sortowanie lub łamanie.

    Patrz: C++ iterate or split UTF-8 string into array of symbols?

2
  1. Okna wewnętrznie tylko robi UTF-16, więc jeśli chcesz obsługiwać znaki międzynarodowe jesteś zmuszony do przejścia na ich wersje widechar używać OS nazywa się odpowiednio. Wydaje się, że nie ma żadnego wsparcia dla wywoływania czegoś takiego jak CreateFileA() z wielobajtowym ciągiem znaków UTF-8 i sprawiają, że wygląda on prawidłowo. Czy to jest poprawne?

Tak, zgadza się. Warianty funkcji *A interpretują parametry łańcucha zgodnie z aktualnie aktywną stroną kodową (która jest Windows-1252 na większości komputerów w USA i Europie Zachodniej, ale często mogą to być inne strony kodowe) i konwertują je na UTF-16. Istnieje strona kodowa UTF-8, jednak AFAIK nie ma sposobu, aby programowo ustawić aktywną stronę kodową (istnieje GetACP, aby uzyskać aktywną stronę kodową, ale nie odpowiadającą SetACP).

  1. w C, niektóre wiele bajtów wspierania funkcji (_mbscat, _mbscpy itp), jednak w oknach typu znak zdefiniowany jako unsigned char * dla tych funkcji. Biorąc pod uwagę, że seria funkcji mbs nie jest kompletnym zbiorem (tzn. Nie ma _bbstol do konwertowania wielobajtowych łańcuchów na długie, na przykład), jesteś zmuszony do korzystania z niektórych wersji char * wersji funkcji uruchomieniowych, co prowadzi do problemów z kompilatorem z powodu podpisanej/niepodpisanej różnicy między tymi funkcjami. Czy ktoś nawet z nich korzysta? Czy po prostu robisz duży stos rzucania, aby obejść błędy?

Rodzina funkcji mbs* prawie nigdy nie używany, w moim doświadczeniu. Z wyjątkiem mbstowcs, mbsrtowcs i mbsinit te funkcje nie są standardowe C.

  1. W C++ std :: string ma iteratory, ale są one oparte na char_type, a nie punktów kodowych. Więc jeśli zrobię ++ na std :: string :: iterator, otrzymam następny char_type, a nie następny punkt kodowy. Podobnie, jeśli wywołasz std :: string :: operator [], otrzymasz odwołanie do char_type, który ma wielki potencjał, aby nie być kompletnym punktem kodowym. Więc w jaki sposób jeden iterować std :: string według punktu kodowego? (C ma funkcję _mbsinc()).

myślę że mbrtowc(3) byłoby najlepszym rozwiązaniem tutaj do dekodowania jeden punkt kodu ciąg wielobajtową.

Ogólnie rzecz biorąc, uważam, że najlepszą strategią dla wieloplatformowej zgodności z Unicode jest robienie wszystkiego w UTF-8 wewnętrznie za pomocą znaków jednobajtowych. Gdy potrzebujesz wywołać funkcję Windows API, przekonwertuj ją na UTF-16 i zawsze wywołuj wariant *W. Większość platform innych niż Windows używa już UTF-8, dzięki czemu korzystanie z nich jest bardzo proste.

+0

Niestety, 'mbrtowc' nie dekoduje punktów kodowych w systemie Windows. –

9

Wystarczy zrobić UTF-8

Istnieje wiele bibliotek wsparcie dla UTF-8 w każdym plaftorm, także niektóre są multiplaftorm też. Funkcje API UTF-16 w systemie Win32 są ograniczone i niespójne, jak już zauważyłeś, więc lepiej zachować wszystko w UTF-8 i konwertować do UTF-16 w ostatniej chwili. Istnieją również przydatne opakowania UTF-8 dla Windows API.

Ponadto, na dokumentach na poziomie aplikacji, UTF-8 jest coraz bardziej akceptowany jako standard. Każda aplikacja do obsługi tekstu akceptuje kodowanie UTF-8 lub w najgorszym przypadku pokazuje go jako "ASCII z niektórymi dingbami", podczas gdy jest tylko kilka aplikacji obsługujących dokumenty UTF-16, a tych, które tego nie robią, jako "partie i partie" białych znaków! "

+0

+1 Dokładnie to, co właśnie pisałem ... – Damon

+2

+1, za wspieranie pomysłów utf8everywhere.org –

+1

Dodałbym całkiem dobre referencje, dlaczego UTF-8 powinien być używany w dowolnym miejscu http://utf8everywhere.org/ –