2010-05-29 4 views
27

Analizując atrybuty UTF-16 i UTF-8, nie mogę znaleźć żadnego powodu, aby preferować UTF-16.Czy istnieje jakikolwiek powód, aby preferować kodowanie UTF-16 nad UTF-8?

Jednak sprawdzając Javę i C#, wygląda na to, że ciągi i znaki są tam domyślnie UTF-16. Myślałem, że może to wynikać z przyczyn historycznych, a może ze względów wydajnościowych, ale nie mogłem znaleźć żadnych informacji.

Ktoś wie, dlaczego te języki wybrały UTF-16? I czy istnieje jakikolwiek ważny powód dla mnie, aby to zrobić?

EDIT: Tymczasem ja również this answer, co wydaje się istotne i ma kilka ciekawych linków.

+3

Poza moją odpowiedź, chciałbym powiedzieć, że .NET/C# wybrali UTF-16, ponieważ jest to „native” kodowanie Windows: łatwiej jest współdziałanie z natywnym systemie Windows, jeśli jesteś przy użyciu to samo kodowanie. –

+1

Do jakich celów wybierasz kodowanie? UTF-16 jest rozsądnym wyborem do obsługi ciągów w pamięci, podobnie jak 'wchar_t', który będzie UTF-16 na Windowsie i zwykle na UTF-32 gdzie indziej. Ale w przypadku protokołów on-the-wire i przechowywania plików, UTF-8 jest prawie zawsze najlepszym wyborem. – bobince

+2

@codeka: Zgadzam się (dał +1), ale można również zadać pytanie "dlaczego jest natywne kodowanie systemu Windows UTF-16, a nie UTF-8?". –

Odpowiedz

31

Języki wschodnioazjatyckie zazwyczaj wymagają mniejszej pamięci w formacie UTF-16 (2 bajty wystarczają na 99% znaków języka wschodnioazjatyckiego) niż UTF-8 (zwykle wymagane jest 3 bajty).

Oczywiście dla języków zachodnich UTF-8 jest zwykle mniejszy (1 bajt zamiast 2). W przypadku plików mieszanych, takich jak HTML (tam, gdzie jest dużo znaczników), jest to znaczna część.

Przetwarzanie UTF-16 dla aplikacji trybu użytkownika jest łatwiejsze niż przetwarzanie UTF-8, ponieważ pary zastępcze zachowują się prawie tak samo, jak zachowują się łączące się znaki. Zatem UTF-16 może być zwykle przetwarzany jako kodowanie o stałym rozmiarze.

+1

+1 Do prawidłowego scharakteryzowania liczby bajtów na znak w UTF-16 i UTF-8. – Joren

+1

Uważam, że kodowanie UTF-8 może kodować do 4 bajtów, co praktycznie uniemożliwia korzystanie z UTF-16 i UTF-32. –

+1

@Sir Psycho: UTF-8 to kodowanie o zmiennej długości, które jest bardziej skomplikowane w przetwarzaniu niż kodowanie o stałej długości. Zobacz także moje uwagi na temat odpowiedzi Gumbo: w zasadzie kombinacja znaków istnieje we wszystkich kodowaniach (UTF-8, UTF-16 i UTF-32) i wymagają one specjalnej obsługi. Możesz użyć tej samej specjalnej obsługi, której używasz do łączenia znaków, aby obsługiwać pary zastępcze w UTF-16, więc * w przeważającej części * możesz zignorować surogaty i traktować kodowanie UTF-16, podobnie jak w przypadku stałego kodowania. –

2

Dla wielu (większości?) Aplikacji, będziesz miał do czynienia tylko ze znakami w Basic Multilingual Plane, więc możesz traktować UTF-16 jako kodowanie o stałej długości.

Pozwala to uniknąć całej złożoności kodowań o zmiennej długości, takich jak kodowanie UTF-8.

+3

+1 w rzeczywistości Myślę, że Unicode w wersji 1 miała tylko podstawowe znaczenie, dlatego liczba platform przyjmujących 16 bitów byłaby odpowiednia dla prostego typu danych znakowych. –

+1

"Myślę, że Unicode w wersji 1 miała tylko podstawowe" - tak, to prawda, więcej szczegółów tutaj: http://en.wikipedia.org/wiki/UTF-16/UCS-2 – Joe

+5

To jak powiedzenie "wiele programów tylko troszcz się o ASCII, więc możesz traktować UTF-8 jako kodowanie o stałej długości. " – dan04

3

To zależy od oczekiwanych zestawów znaków. Jeśli spodziewasz się dużego wykorzystania punktów kodowych Unicode poza 7-bitowym zakresem ASCII, możesz uznać, że UTF-16 będzie bardziej kompaktowy niż UTF-8, ponieważ niektóre sekwencje UTF-8 mają więcej niż dwa bajty.

Również ze względów wydajności Java i C# nie biorą pod uwagę zastępczych par podczas indeksowania ciągów. Spowoduje to całkowite uszkodzenie w przypadku użycia punktów kodowych reprezentowanych przez sekwencje UTF-8, które zajmują nieparzystą liczbę bajtów.

+0

Czy mógłbyś rozwinąć temat "Java i C# nie biorą pod uwagę zastępczych par podczas indeksowania string "? – Oak

+1

Jeśli masz ciąg w C# (lub Java), który zawiera pary zastępcze (SPs są używane do kodowania znaków spoza normalnego zakresu dwóch bajtów), każda para będzie liczona jako dwa 16-bitowe znaki, a nie jako 1 Punkt kodowy Unicode Przynajmniej do celów indeksowania i raportowania długości – corvuscorax

6

Wyobrażam sobie, że C# używa UTF-16 wywodzi się z rodziny systemów operacyjnych Windows NT używających wewnętrznie UTF-16.

sobie wyobrazić, istnieją dwa główne powody, dla których Windows NT używa UTF-16 wewnętrznie:

  • Dla wykorzystania pamięci: UTF-32 traci dużo miejsca do zakodowania.
  • W celu zwiększenia wydajności: kodowanie UTF-8 jest znacznie trudniejsze niż kodowanie UTF-16 w wersji . W znakach UTF-16 jest albo znak wielorodzajowej płaszczyzny podstawowej (2 bajty) albo para zastępcza para (4 bajty). UTF-8 znaków może być w dowolnym miejscu od 1 do 4 bajtów.

W przeciwieństwie do odpowiedzi udzielonych przez inne osoby - nie można traktować UTF-16 jako UCS-2. Jeśli chcesz poprawnie iterować po rzeczywistych znakach w ciągu znaków, musisz użyć funkcji iteracji przyjaznych dla Unicode. Na przykład w C# musisz użyć StringInfo.GetTextElementEnumerator().

W celu uzyskania dalszych informacji, to strona na wiki Warto przeczytać: http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

+0

Aha, i nie zapomnij o łączeniu znaków! (Którą obsłuży również "GetTextElementEnumerator".) –

+2

"... nie możesz traktować UTF-16 jako UCS-2" - ale wiele udanych aplikacji w świecie rzeczywistym robi to i ucieka, ponieważ używają tylko znaków BMP. – Joe

+0

Bardzo przydatny link, dzięki! – Oak

3

UTF-16 może być bardziej wydajny reprezentacji znaków w niektórych językach, takich jak chiński, japoński i koreański gdzie najbardziej znaki mogą być reprezentowane w jednym 16-bitowym słowie. Niektóre rzadko używane znaki mogą wymagać dwóch 16-bitowych słów. UTF-8 jest generalnie znacznie wydajniejszy do reprezentowania znaków z zachodnioeuropejskich zestawów znaków - UTF-8 i ASCII są równoważne w zakresie ASCII (0-127) - ale mniej wydajne w językach azjatyckich, wymagające trzech lub czterech bajtów do reprezentowania znaków, które może być reprezentowany przez dwa bajty w UTF-16.

UTF-16 ma przewagę jako format in-memory dla języka Java/C#, w którym każdy znak w podstawowej płaszczyźnie wielojęzycznej może być reprezentowany w 16 bitach (patrz odpowiedź Joe) i niektóre wady UTF-16 (np. mylący kod opierający się na \ 0 terminatorach) są mniej istotne.

10

@Oak: to zbyt długo na komentarz ...

nie wiem o C# (i byłoby naprawdę zaskoczony: to znaczy, że po prostu kopiowane Java zbyt dużo), ale za to jest Java proste: Java została opracowana przed wydaniem Unicode 3.1.

Z tego powodu było mniej niż 65537 punktów kodowych, stąd każdy kod kodowy Unicode był nadal dopasowany do 16-bitów i tak narodził się Java char.

Oczywiście doprowadziło to do szalonych problemów, które są nadal wpływających programistów Java (jak ja) Dzisiaj, gdzie masz metodę charAt które w niektórych przypadkach nie zwraca ani znak Unicode ani kodowy Unicode oraz sposobu (dodane w Javie 5) codePointAt, która przyjmuje argument, który nie jest liczbą punktów kodowych, które chcesz pominąć! (musisz dostarczyć do codePointAt liczbę Java char, którą chcesz pominąć, co czyni ją jedną z najmniej poznanych metod w klasie String).

To jest zdecydowanie szalony i mylący większość programistów Java (większość z nich nawet nie jest świadoma tych problemów) i tak, to z historycznego powodu. Przynajmniej była to wymówka, która pojawiła się, gdy ludzie oszaleli po tym wydaniu: , ale to dlatego, że Unicode 3.1 nie został jeszcze udostępniony:.

:)

Powiązane problemy