Mikhail писал(а):Кто-нибудь вообще может объяснить зачем вообще нужен UTF-16? UTF-8 лучше подходит и с ним меньше проблем, ИМХО.
UTF-8 хорошо подходит для фиксированных строк. Ну или для строк, которые надо только складывать. А вот если нужен простой и быстрый способ доступа к произвольному символу, то тут уже желателен UTF-16, потому что в нём символы "фиксированной" длины, в отличие от UTF-8, где длина символа может изменяться от 1 до 4 байт (в пределе до шести, но стандарт такие сейчас запрещает).
Это если коротко. Если длинно, то надо смотреть историю уникода. Изначально UTF-8 не было, когда решили объеденить все символы в одну таблицу, просто выбрали символ, длиной в 2 байта (65536 символов хватит всем). И первоначально разбазаривали их настолько, что во второй версии стандарта там был даже клинконский... Затем во время разработки операционной симтемы Plan9 был придуман UTF-8, который имел важное преимущество - вся латиница автоматически оказывалась уникодом. Кроме того, стандарт пришёлся ко двору в unix, где не пришлось переделывать файловые системы, т.к. имя файла в них было просто потоком байт. И для поддержки файлов на языках, отличных от английского, при монтировании приходилось указывать кодовую страницу. Эта проблема и сейчас осталась на флешках с FAT. Правда теперь пропали строгие пределы длины имени файла, если раньше они были 255
символов, то теперь - 255
байт. А уж сколько символов влезет - как повезёт.
Затем начались неприятности у двухбайтных символов. Дело в том, что они не были UTF-16, они были UCS2. Казалось бы в чём разница? А она была. Дело в том, что народ слегка просчитался в предельном количестве символов, которое необходимо человечеству. Не правильно учли интересы китайцев и японцев, не продумали нормализацию (сейчас объясню, что это такое). Пришлось даже выкинуть клингонский (пичалька).
Итак нормализация. Что это такое? А это вот что. Представье себе европейские символы, проде буквы "ё", только их там больше и они не являются неотъемлимой частью буквы, а могут то быть, то не быть. Это называется диактрические знаки. Есть они даже в англйском, хотя многие не подозревают об этом. Например, слово "сотрудничество" правильно писать "
coöperation", чтобы показать, что двойное "o" не читается, как "у". (Правда сами англичане об этом знают и по этому на практике никогда не пишут.
)
Так вот, вопрос в том, как кодировать такие символы. В однобайтных кодировках для таких букв выделялись отдельные символы, но теперь по ряду причин решили делать символы составными. Т.е. наше "ö" записывается как уникодный символ "маленькая латинская буква о" + "две точки сверху". И всё бы ничего, но во первых старое написание уже попало в стандарт, где для "ö" существовал отдельный символ "маленькая латинская o с двумя точками сверху", а во вторых
мы только что сломали кучу алогритмов, которые были уверены, что два байта - один символ.
Пришлось допиливать стандарт и проводить разъяснительную работу. Во первых, было введено понятие "кодовая точка" (code point). Смысл такой - кодовая точка - это или символ или диактрика, которая меняет предыдущий символ или ещё какая-нибудь служебная последовательность. А сам символ состоит из одной или более кодовых точек. Причём, не важно, UTF-8 у вас или UCS2. Как вы можете догадаться, это слегка неудобно. Кроме того, если начать кодировать символы как угодно, то начнётся полная анархия. Строки, которые состоят из одинаковых символов перестанут быть равны друг другу. Так пришли к идее нормализации. Их целых 4 вида, но наиболее популярная NFC - все символы хранятся в максимально компактном виде. И в 99% случаев мы имеем "кодовая точка" = символ.
Незадолго до этого популяризировалась Java, привнеся внутреннюю реализацию строк на UTF-16, что занимало больше памяти, но позволяло быстро обращаться к символу по его номеру.
Однако, на этом история не кончилась. Оказалось, что для некоторых менее распространённых языков, с учётом новой системы двух байт уже нехватает и полную кодовую точку пришлось расширять до 4 байт, выведя UCS4. А UCS2 заменили на UTF-16, который почти такой же, но для определённого диапазона полная кодовая точка занимает уже два UTF-16 блока, т.е. 4 байта. Это окончательно поставило крест на идее обращения к символу по номеру, как к элементу массива, но тем не менее переход на UCS4 так и не произошёл, т.к. когда это всё происходило, память ещё не ставили гигабайтами и всех задушила жаба. А теперь уже так сложилось, как сложилось.
Однако, тем не менее, у UTF-16 есть небольшое преимущество. Итерация по символам реализуется проще, чем в UTF-8, т.к. каждое слово (2 байта) надо всего лишь проверить на вхождение в заданный диапазон. Есть так же и выигрыш в памяти, по сравнению с UTF-8. Но только для мультиязычных текстов. Так например, кириллица в UTF-8 занимает обычно 3 байта на символ, так что храня текст в UTF-16 вы немного выиграете в памяти.
Резюмируя: UTF-16 существует по историческим причинам, как компромис по потреблению памяти и скорости обработки, как правило несущественный в наши дни.