Java Core собеседование: кодировки
Добрый день.Меня зовут Головач Иван, я занимаюсь интенсивным обучение Java и натаскиванием на собеседования.В итоге у меня скапливается достаточно большое количество интересного кода по каждому разделу Java Core.Я бы хотел им поделиться со следующими целями:1. Возможно, они подтолкнут кого-то к более детальному изучению языка и стандартной библиотеки.2. Возможно, они помогут кому-то с прохождением/проведением собеседования.3. Возможно, мне удастся развеять некоторые, по моему мнению неправильные, представления о Java Core, как теме на 1 неделю ограничивающуюся простейшими языковыми конструкциями типа switch/for/if и классами String/ArrayList/InputStream.Итак — начну:.Примеры кода:Почему строка в которой в два раза больше букв (2 вместо 1) занимает в только 1.5 раза больше места?
.Если UTF-8 так хорош (как все говорят), почему он занимает так много места (и чем он тогда хорош)?
-------------------------------------------UPD:Использование latin1, как заметил Mike Gorchak приводит к некорректному результату, лучше взять cp1251.
-------------------------------------------.А что такое этот самый «UTF», если «их» так много?.Как строка из одного символа может сохраняться в разные размеры байтовых массивов.Все таки в этой строке ОДИН символ или ДВА?
.Терминология:В области терминологии хорошо бы понимать, что значат термины:character, character set, coded character set, glyph, font, Unicode, codeunit, codepoint, charset, Byte Order Mark (BOM), endianless, Big Endian (BE), Little Endian (LE), variable length encoding, fixed length encoding, UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, UTF-32LE, ASCII, Basic Multilingual Plane (BMP), supplementary characters, surrogate pairs..P.S. Сможет ли кто-то дать наиболее просты и корректные объяснения данных терминов?:).P.P.S. Ближайший набор в группу Java Core — 5 декабря 2013 года.Ближайший набор в группу Junior Java Developer — февраль 2014.Больше Вы можете узнать по:skype: KharkovITCoursesemail: KharkovITCourses@gmail.com
В избранное В избранном 0
Похожие топики Лучшие комментарии пропуститьМне, честно говоря непонятно, почему тут все так на Головача накинулись?Напишу свой скромный взгляд со стороны обучающегося (вернее самообучающегося).Некоторое время назад совершенно случайно здесь же набрел на ссылку на его курсы, открыл первую попавшуюся видеозапись лекции (попалась по JUnit and Hamcrest ) и на следующий же день побежал заказывать и покупать в Розетке 2TB винчестер, чтобы пока его записи лекций выложенные им на youtube не начали исчезать их все успеть себе сохранить по курсам Core, Junior и Аддоны.На сегодняшний момент самостоятельно, переписывая код с видео, прошел большую часть курса Core так что считаю, что какое-то мнение о курсе с точки зрения обучающегося высказать право имею.Так вот — лично для меня(моего склада ума, психотипа и т.д.) Головач оказался просто божественным преподавателем (я таких за весь ВУЗ пару человек вспомнить могу только).В чем его высокий уровень преподавательского мастерства выражается (опять же с моей точки зрения):1. Он очень хорошо придумывает и подбирает абстракции при объяснении устройства JVM, работы компилятора, ООП и т.д. 2. Очень хорошо удерживается на уровне преподавания материала — его не заносит в дебри из которых потом некоторые преподаватели выбраться не могут и до конца лекции и т.д. — все идет четко, последовательно и по плану.3. Его лабы составлены, как если помните в СССР книжки издавались типа «100 загадок и отгадок.», т.е. ответ на загадку (лабу) , если ты нашел правильный ответ — очевиден, что в принципе мне как «халявному слушателю» его курсов, не имеющему возможности послать его проверяющему на проверку является просто громадным плюсом. Т.е. если ты промучался над какой-то лабой пару дней, но ответ нашел — ты сразу понимаешь, что нашел правильный ответ.4. Его лекции интересны и не вызывают желания заснуть — он приводит интересные примеры, показывает интересные фичи работы компилятора или JVM, под конец утомительных, высоконагруженных материалом лекций «юморит», чтобы слушатели могли на пару секунд расслабиться и потом опять в тонусе его дальше слушали.5. В отличие от некоторых Российских курсов(не буду их называть), которые ориентированы на то, чтобы дать поверхностные знания и обмануть собеседующего (ну типа той хрени которая меня в ВУЗе раздражала больше всего: «Вы это учите, чтобы сдать экзамен.») у Головача, кроме кучи тестов и т.д. идет довольно глубокое преподавание материала. По каждой из тем, которые я прошел и все лабы выполнил лично для меня не составляет проблемы «копать вглубь», т.к. я понимаю как это работает и что мне объясняет автор, забурившийся в конкретные ньюансы данной темы в своем проекте. А не так — тему прошел, все тесты сдал, а потом открыл узкоспециализированную статью на хабре по этой теме и ничего не понял, т.к. учил тему, чтобы тесты сдать.6. Честно рассказывает о том, как построены производственные отношения между программистом и работодателем с точки зрения наемного работника, о типах карьерного роста в аутсорсе и т.д. Нет, не с позиций «как поиметь работодателя, а лучше нескольких и сразу», а опять же четко, структурировано говорит о различных вариантах, подходах, стратегиях — короче перечисляет возможные пути роста, чтобы каждый мог выбрать тот, который подходит именно ему.
Да наверное можно много чего еще перечислить, но могу сказать одно — лично мне он совершенно бесплатно дал возможность изучить Java до уровня джуна по записям своих лекций, причем этот процесс скорее похож на «прокачку» в какой-нить MMORPG типа Aion, LA2, WOW — своим стилем преподавания он меня заставил «задротить левел в Java» если так можно выразится — изучение лекции за лекцией идет как получение уровней в игре — взял один, хочется быстрее взять следующий.
Не знаю, поможет ли мне его Core-курс попасть на декабрьские курсы GlobalLogic BaseCamp в Киеве или нет (т.к. курс его Java Junior, я боюсь, что только начну осваивать к началу конкурса на эти курсы) — если пройду конкурс, то обязательно отпишусь, но посоветовать его Курсы то ли в виде самоизучения (если у вас мозги потянут и усидчивости хватит часами самостоятельно их осваивать) то ли записаться к нему на заочные или очные(если Вы из Харькова) если Вам нужно живое общение с преподавателем я бы посоветовал.По крайней мере — скачайте его первые пару лекций и посмотрите, уверен, что у большинства новичков в Java из тех кому программирование хоть как-то интересно как процесс, а не для того, чтобы «бабла срубить по-быстрому» возникнет желание в той или иной форме.
Вобщем-то этим длинным постом я хотел бы как-то отблагодарить Ивана Головача за то, что фактически благодаря ему я имею возможность с удовольствием освоить Java и надеюсь, что хотя-бы один человек, прочитав этот отзыв посмотрит своими глазами записи его лекций и запишется к нему на курсы.
212 комментариевтема кодировок — отдельная тема. к изучению Java она имеет косвенное отношение. лучше не заморачиваться на таких мелочах, сколько символов, сколько кодовых точек и т.п., а сосредоточиться на существенных вещах. если разбирать дотошно так все вопросы — то жизни не хватит и учащийся будет «вечным студентом».
Провожу серию вебинаров как раз на эту тему, можете присоединиться Практический online-интенсив «Подготовка к Java Interview» 10.01.2016
Я себе сделал такую шпаргалку:
Юникод — это стандарт кодирования символов для большинства языков мира, включая вымершие, а также много различных вспомогательных символов (например, математических). Юникод разрабатывает одноименный консорциум (www.unicode.org). У каждого символа есть официальное именование (например, «latin small letter a») и код (code point) — число от 0 до 10FFFF.
Символ (Character) — наименьший компонент письменного языка, который имеет семантическое значение. Еще одно значение символа — абстрактный символ — единица информации, используемая для управления, организации и для представления текстовой информации.Глиф — графическое представление символа. Некоторые символы могут иметь различное начертание, например в зависимости от позиции в слове. Но это уже проблемы системы вывода на экран. Сборище глифов, обычно одного стиля, называют шрифтом.
Character set — Набор элементов для представления текстовой информации. Т.е. это просто набор любых символов, например строчные буквы английского алфавита.
Coded character set — character set, у которого каждому элементу присвоен числовой код (code point).
С charset немного сложнее — юникод определяет его просто как синоним coded character set (www.unicode.org/. x.html#charset, а в java это означает encoding — правило отображения кодов символов (code points) в кодовые единицы (code units).
Code point (кодовая точка)- любое значение в пространстве кодов юникода, т.е. сами коды символов.Code unit (кодовая единица)- битовые последовательности, с помощью которых можно закодировать code point. В юникод используют 3 типа code unit — 8ми битовые (byte), 16ти битовые и 32х битовые.В большинстве языков программирования (включая java) для внутреннего представления (класс String) используют 16 битные code units, т.е UTF-16. Поэтому, когда вы у строки вызываете метод length, вы получите длину в кодовых единицах, а не количество символов в строке.
Переходим к самому интересному :)UTF — Unicode Transformation format — способ кодирования кодов символов в последовательности байт.Есть формы кодирования UTF, а есть схемы. И вообще говоря это не одно и то же. Формы кодирования — правила разложения кода символа в кодовые единицы (code units). А схема кодирования — правила сериализации кодовых единиц в байты (например, при записи на диск).Есть 3 формы кодирования — UTF-8, UTF-16, UTF-32.В UTF-32 каждый код символа кодируется 4мя байтами, т.е. это кодирование с фиксированной длиной (fixed length encoding).В UTF-8 каждый символ юникода кодируется последовательностью от одного до 4х байт по хитрой схеме (en.wikipedia.org/. -8#Description, т.е. это variable length encoding. Преимущества данного метода в том, что коды ascii (кодировка, придуманная американцами, соответствуе первым 127 символам в наборе unicode) кодируются без изменений, одним байтом.В UTF-16 для кодирования кодов символов с номерами больше U+FFFF (их называют supplementary characters) используют суррогатные пары — коды из диапазона U+D800-U+DFFF. Т.е., символы с кодами больше U+10000 кодируются двумя 16ти битными парами. Коды из диапазона суррогатых пар не должны встречаться поодиночке. Пространство кодов с кодами U+0000 — U+FFFF называют Basic Multilingual Plane (BMP). Схем кодирования семь — UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, UTF-32LE.BE и LE означают big endian или little endian, т.е. в каком порядке идут байты, сначала старшие или сначала младшие. Если не указано и нет BOM, то следует трактовать как BE.BOM — byte order mark — отметка порядка байтов. Символ с кодом FEFF (неразрывный непечатный пробел) записывают в начале текста. При вычитке проверяют первый байт, если это BOM и код FFFE, значит порядок little endian. Если код FEFF или это не BOM, то порядок big endian.Никто не запрещает записать BOM в текст, закодированный в UTF-8 — но делать так не стоит, особенно в unix-подобных системах. У Microsoft особое мнение по этому поводу,поэтому notepad таки вставляет в текст в UTF-8 BOM :)Если вы такой текст прочитаете в java, получите 3 кракозябла в начале.
Существует также стандарт кодирования от ISO/IEC, ISO-10646, который совместим в юникодом по кодам символов и названием этих символов
P.S.И не пытайтесь написать свой кодер\декодер из\в UTF-8. У вас не получится (написать полностью корректный, который правильно обрабатывает многочисленные malformed последовательности). А если и получится, то значит вы убили кучу времени на изобретение велосипеда %)
насчет charset в java я не прав — там это тоже coded character set.
import java.nio.charset.*;import java.util.*;
public class Encode2
После вывода мы получим список доступных #charset#ов.То есть #charset#ы это правила кодирования, перечисленные выше выводом на консоль.
Этот текст был в первом варианте, моего ответа Ивану, но я посчитал его очень громоздким, и урезал его на половину. Надеюсь не чего лишнего не вырезал).
ну как возможность подвигать байты, то да, полезно )
кодовые единицы это code units, их количество и возвращает метод length. А str.codePointCount(0, 2). вернет количество кодовых точек (кодов юникода).
спасибо большое. мне помог этот комментарий, смог разложить все по полочкам
Символ (character) — единица информации, которая соответствует письменному символу (графема) естественного языка общения. «?», «A», «+», к примеру. Каждая из графем (или набор графем), отображенных на Вашем мониторе, представляет собой глиф. Глиф (glyph), как единица графики, является графическим отображением графемы. Glyph символа процента или «собака», в конкретном случае, выглядят как «%», «@».Определенный стиль отображения глифа, с учетов размера, насыщенности, удобочитаемости и других характерных особенностей, это и есть шрифт (font). Примером современных компьютерных font’ов могут быть всем известные Arial, Calibri, Times New Roman и др.В промежутке между тем как символ языка общения в виде character отобразится на мониторе (к примеру) в виде glyph’а определенного font’а, происходит «конклав» кодировки. Процесс перевода каждого character на машинный язык требует определенного стандарта. Coded character set определяет как представить character в виде целого числа, которое называется code point. Для примера, символ представляющий большую букву «А» (лат.) имеет номер 65 (в ASCII). Один из первых coded character set — ASCII (American Standard Code for Information Interchange) — американский кодировочный стандарт для печатных символов и некоторых специальных кодов. ASCII представляет собой кодировку из 128 символов для представления цифр, латинских символов, знаков препинания и управляющих символов, каждому символу соответствует битное значение целого числа. В целом на этом можно было бы и остановиться, если бы не наличие многих других символов различных письменностей, которые в ASCII учтены не были, да и битная кодировка нравилась не всем. Что привело к развитию других систем кодирования символов — возникла, как минимум, проблема совместимости. Таким единым стандартом является Unicode (юникод) — стандарт кодирования символов, который представляет практически все возможные знаки письменности. Изначально кодовое пространство Unicode включало 65536 code points. В дальнейшем кодовое пространство Юникода было расширено до 1 112 064 code points. Где первые 65 536 - первоначальное пространство представлений символов, 2048 — количество значений забронированных для элементов суррогатных пар (от 55 296 до 57 343), 1 048 576 — пространство для символов не вошедших в первый диапазон (Basic Multilingual Plane) — supplementary characters. В итоге пространство Юникода разбилось на 17 плоскостей, где плоскость — Basic Multilingual Plane — со всеми наиболее часто используемыми символами. Один из методов, с помощью которого Юникод мапится на character set — Unicode Transformation Format encoding (UTF) . Этот метод породил 3 известные кодировки: UTF-8, UTF-16, UTF-32
>> [65] — использована кодировка UTF-8 — битный формат преобразования Юникода, что для символа «A» являет собой один байт и совпадает со значением кодировки ASCII. Первые символы Unicode полностью соответствуют кодировке ASCII.
>> [-2, -1, 0, 65] — кодировка UTF-16 — битный формат преобразования Юникода. UTF-16 имеет представления UTF-16BE и UTF-16LE, что значит Bid Endian и Little Endian — по сути требование компьютерной архитектуры, которая использует многобайтные значения со старшим байтом в начале (Little Endian) или старшим байтом в конце (Big Endian). BE и LE — метки порядка байт или понятным языком byte order mark — BOM. По умолчанию UTF-16 использует Big Endian, чтобы неявно это обозначить, в начало строки (в нашем случае «A») вставляется два байта обозначающие то самое Big Endian. Эти байты [-2, −1] в начале сроки, U+FEFF и U+FFFE в шестнадцатеричном представлении — непечатные символы в Unicode. >> [0, 65] >> [65, 0] — теперь легко можно понять порядок байт и отсутствие BOM в начале строки. >> [0, 0, 0, 65] >> [0, 0, 0, 65] >> [65, 0, 0, 0] — такая же ситуация как и в случае с использованием кодировки UTF-16 за исключением того что кодировка UTF-32 — система кодирования фиксированной длины Fixed width encoding — каждый символ Юникода должен быть представлен в виде 32 бит. Преимущество UTF-32 заключается в том что каждый code point представляет конкретный code point юникода. Тем не менее, UTF-32 достаточно тяжеловесный по тем же причинам.
System.out.println("A".getBytes("UTF-16").length); System.out.println("AA".getBytes("UTF-16").length); >> 4 >> 6 >> 4 — очевидно почему 4 байта(неявное указание BE занимает первые 2 байта). >> 6 — каждый следующий символ кодируется байтами, как это и предусмотрено системой кодирования UTF-16, поэтому добавление следующего такого же символа добавляет всего два байта.
char ch; ch = 0x0001; ch = 0x0111; ch = 0x1111; >> [1] >> [-60, -111] >> [-31, -124, -111] Учитывая то, что UTF-8 (как и UTF-16) — Variable width encoding — система кодирования, использующая коды различной длинны для представления символов. ch = 0×0001 — входит в диапазон code points 0×0000 — 0×007F, который представляет символы одним байтом — 0xxxxxxx.ch = 0×0111 — code points 0×0080 — 0×07FF — 2х байтное представление 110xxxxx 10xxxxxx.ch = 0×1111 — code points 0×0800 — 0xFFFF — 3х байтное представление 1110xxxx 10xxxxxx 10xxxxxx.Где каждый байт — Code unit — минимальный набор бит, который представляет единицу кодированного текста. Для UTF-16 — code unit состоит из 16 бит и из 32х для UTF-32.
>> � >> 2 >> 1 >> ? >> ? В этой строке один символ.Метод length() возвращает кол-во знаков char в строке. И если бы, допустим, мы на основе этого метода пытались выделить количество ячеек для имени китайца на китайском языке, то ячеек всегда оказывалось бы больше чем китайцу нужно. Метод codePointCount(0, 2) вернул количество символов соответствующих стандарту Юникод(то что нужно китайцу) — 1 символ. Символы, которые лежат выше BMP или следующие за code point U+FFFF (65535) называются supplementary characters. Это символы Юникода — пары знаков char, которые называются суррогатными парами (surrogate pair). Два знака char — суррогатное представление символов Юникода в диапазоне от U+10000 до U+10FFFF.
вроде все мы с конспекта черпаем (за исключением reality hacker, он с момента зачатия все знает), видимо конспекты разные))
Меня не зачинали, я самосгенерировался
агентура не спит?
Код BOM — U+FEFF, а не U+FFFE. А U+FFFF вообще тут ни при чём.
спасибо! сам не ведаю, чего творю.
После того как посмотрел лекцию Ивана: www.youtube.com/. UuyfzxU4brinuTI мне многое стало понятно )).Насчёт того нужна или нет информация о кодировках — для меня эта лекция была очень полезна, я например раньше не понимал как настроить IDE чтобы русские комментарии, русский вывод на консоль нормально отображался в разных редакторах. Почему файл Питона набранный в Линукс не хочет отображать нормально русские буквы в Виндоус. Как закоренелый пользователь Виндоус я признавал только 1251. Когда то я писал перекодировщики из разных досовских кодировок в cp1251, но Unicode оставался для меня тайной покрытой туманом. Вроде и ясно что два байта на символ, но всё равно знания какие-то зыбкие. Но теперь то я обрёл уверенность))
Я попытаюсь ответить на вопросы Ивана, и надеюсь он исправит меня если я где-нибудь ошибусь.Основная причина описанных Иваном странностей связана с различными интерпретациями Unicode’a. Надо сказать, что Unicode — это не шрифт, это не кодировка и не кодовая страница (code page). Unicode — это множество пронумерованных символов (coded character set). Каждому символу присвоен порядковый номер. Каждый символ (character) входит в это множество один раз. То есть символ латинского алфавита «а», буква кириллицы «Э», символ градусов Цельсия «°» и многие другие имеют свой номер. Например латинская «а» имеет номер 97, русская «Э» — 1069 (0×42D), а египетский иероглиф похожий на самолёт имеет номер — 0×13266 (78_438). Когда на землю прилетят инопланетяне их символы также пронумеруют и внесут в это множество.Символ «Э» может иметь огромное количество возможных форм отображения(glyph). Маленькие, большие, bold, italic, Times New Roman, Arial. Всё это зависит от применяемого шрифта (font) и не имеет никакого отношения к Unicode. Если можно так сказать font’ы и Unicode относятся друг другу перпендикулярно — они не влияют друг на друга.
Как показано выше Unicode имеет в своём составе символы с номером больше 78.000. Как же оперировать с такими символами? Какой выбрать размер данных чтобы их хранить — byte, int, long, char?И тут возникают различные правила отображения Unicode в соответствующие им байты. Это — Charset. Существуют Charset’ы отображающие символ "а«(номер 97) в один байт, в два байта, или в четыре байта. Charset UTF-8 отображает символы от нулевого до в один байт. В этом чарсете выгодно хранить тексты на английском языке. Этот чарсет наверно самый сложный потому что имеет разную длину данных для разных символов. Для русских букв это уже будет два байта, для китайских иероглифов три или четыре (точно я не знаю). Поэтому ch = 0×1, ch=0×111, ch=0×1111 из обсуждаемых примеров и отображаются соответственно в 1, 2 или в 3 байта. Я не буду описывать правила отображения символов в этом чарсете. У меня не получится это сделать кратко (правила там не сложные , но слов понадобится много и ещё картинки придётся рисовать), желающие могут обратиться к Википедии (en.wikipedia.org/wiki/UTF-8.
Charset’ы UTF-16, UTF-16LE, UTF-16BE отображаются на двухбайтные char’ы. Символы от 0 до 65_535 описывают все современные алфавиты мира (Basic Multilingual Plane (BMP)) и описываются двумя байтами. Мертвые языки и дополнительные символы записываются четырьмя байтами.При разработке UTF-16 учитывалось наличие компьютеров с разной архитектурой памяти. Я имею ввиду BigEndian и LittleEndian. В название чарсетов прямо указано какое направление данных в памяти. Для UTF-16 (без LE и BE) порядок байтов определяют первые два байта текста — 0xFF 0xFE (-1 −2) соответствует UTF-16LE , 0xFE 0xFF - BE. Данный нетривиальный приём обозвали Byte Order Mark (BOM), Всё это видно в одном из примеров выше.UTF-32 отображается в четыре байта. Как видно из рассматриваемого примера UTF-32 и UTF-32BE синонимы.
UTF-32 имеет фиксированную длину данных для каждого символа (fixed length encoding), что позволяет легко и быстро его обрабатывать. Осуществлять быстрый поиск, вставку в файлы. UTF-8 и UTF-16 имеют переменный размер для символов (variable length encoding), что не позволяет например найти мгновенно 1_000_000’ый символ в файле. Но за счёт того что символы с номерами не входящими Basic Multilingual Plane найти в документах достаточно сложно в основном применяются именно UTF-8 и UTF-16.UTF-8 и UTF-16 имеют переменную длину и для того чтобы записать достаточно большие символы (для UTF-8 свыше 0×7FF, для UTF-16 свыше 0xFFFF) будут использоваться три или четыре байта, в таких случаях в Java применяются два char’a (их называют supplementary characters или surrogate pairs). Возникающие при этом странности (когда в используемом font’е нет изображения соответствующих символов) показаны в последнем примере
Надо сказать что Unicode не единственный используемый набор символов (coded character set), до стандартизации Unicode на протяжении 40 лет было составлено огромное количество кодовых страниц -ASCII, KOI-8, CP-866, CP-1251. Три последние являются русскими кодировками. Они фактически являются и «coded character set» и " Charset " одновременно. Связанно это с тем что они содержат по 128, 256 символов и отображаются напрямую в один байт. В исправленном примере выше чарсет «latin1» является синонимом чарсета " ASCII «. Да эти чарсеты очень экономны, экономней их могут быть они же самые только зазипованные. Но в современном мире, где пользователь во Вьетнаме открывает веб-страничку американской компании, сайт которой разработали где-то в Индии, при использовании старых чарсетов у него есть довольно большая вероятность увидеть странные «кракозябры». Именно по этой причине Unicode и получил такое распространение.
В середине 90ых произошло событие которое возможно наши потомки через тысячу лет будут считать главным событием этого времени. Нет это не возникновение интернета, не появление компьютеров, не исчезновение СССР. Это событие — появление Unicode. Да, вот так неожиданно!Сколько языков программирования, технических новинок появиться за ближайшую тысячу лет, сколько государств возникнет и распадётся — им нет числа. А Unicode продолжит существовать, к тому времени в него включат алфавиты инопланетян и он будет проходить незаметной нитью сквозь все программные продукты будущего. Он будет присутствовать в комментариях первых программ квантовых компьютеров, при помощи его будут описаны спецификации компьютеров которые придут им на смену, первые семантические процессоры искусственного интеллекта будут пропитаны им. Вся текстовая информация передающаяся по галактической телепатической информационной сети будет описана при помощи Unicode.
System.out.println(Arrays.toString("A".getBytes("UTF-16″)));System.out.println(Arrays.toString("A".getBytes("UTF-16BE")));System.out.println(Arrays.toString("A".getBytes("UTF-16LE")));>> [-2, −1, 0, 65]>> [0, 65]>> [65, 0]
До 0×7F, т.к. 0×7FF — уже воспользовался возможностями переменной длинны?
1.До того как я посмотрел лекцию Ивана, я считал что символы Unicode’а всегда занимают два байта и что их всего 65000 (да, для меня эта лекция была полезной) 2.Проблемы с точной передачей смысла — имелось ввиду то, что (-1 −2) обозначает что дальше данные сохранены в LittleEndian формате3. от 0×7f до 0×7ff UTF-8 сохранит символ в два байта, но в Java это будет всё ещё один char
да, правильно в variable width encoding изменяется количество байт на один символ. (Tо что в этом диапазоне количество байт равно двум) AND (и в диапазоне который был ниже, каждый символ представлялся одним байтом) —> (обозначает что UTF-8 является variable width encoding)Но суррогатные пары появляются только в диапазоне выше 0×7FF
Обманул, оказалось всё сложнее.Проверил себя и выполнил следующий код char c1[] = ; String str1 = new String (c1); System.out.println(Arrays.toString((str1.getBytes("UTF-8")))); System.out.println(str1.length()); >>[-17, -68, -128] >>1 То есть символы выше 0×7FF будут сохраняться в одном char’e
А с суррогатными парами следующая история: Unicode имеет два диапазона [0xD800, 0xDBFF], [0xDC00, 0xDFFF] — в каждом диапазоне по 1024 значения. В этих диапазонах символы не определены. Они используются для того чтобы в UTF-16 отображать символы от 65_536 до 1_100_000. Комбинируя один char из первого диапазона, второй из второго мы получаем суррогатную пару (surrogate pair) и их возможное количество (миллион) определяет множество дополнительных символов (supplementary characters)
Таким образом в UTF16 мы можем закодировать следующее количество символов 65_536 — (1024 +1024) +1024 *1024 .
В UTF-8 и в UTF-32 суррогатные пары не используются это просто пропуск в длинном списке символов.
закодировать можно, но использовать нельзя
можно закодировать символ \u 0xD802, но в UTF-8 он никакой информации не несёт — если он встретился вUTF-8 то это значит скорее всего что файл в данном месте повреждён
какую информацию он несет в УТФ-16?
В UTF-16 с ним в паре должен идти char из второго диапазона [0xDC00, 0xDFFF], то есть возможно 1024 варианта последующих char’ов. Так потенциально образовать 1024 символа Unicode’a.
Для UTF-8 и UTF-32 нет необходимости прибегать к таким сложностям для кодирования символов с номером свыше 65тыс.
Доброе время суток, я как слушатель лекций Ивана, не хотел бы уходить от темы поста;)Начну свой ответ на вопрос Ивана с понятий которые приведены в данной теме, а за тем отвечу на вопросы дабы раскрыть суть:«Character» я понимаю это как уникальный символ отличный от других ( буква, иероглиф; цифра) и т.д. А вот «Character set» это набор этих символов. Может быть, что набор этих символов состоит только из нескольких(морзянка 3 символа, но перекодирование совокупности этих символов нам даст словосочетания) или множества(иероглифы которые в совокупности тоже что-то несут понимающим товарищам). «Сoded character set» нумерация «Character» в «Character set» , допустим у нас есть множество "Character set"ов как в Unicode, каждый из этих наборов находится в каком то диапазоне номеров, например кириллица — это набор "Character set"ов, в нём находится 432 символа (исторических, современных, не славянских и славянских языков (0×0400 до 0xA69F)) почему диапазон, по причине того что некоторые языки могут иметь якобы символы которые забыты, но вдруг кто-то вспомнит о них как это было уже не один раз, и размер юникода всё больше вырастает, но создатели этой последовательности наконец остановились на отметке которая составила 1 112 064 "Character"ов. Это не значит что на нашей планете столько символов было найдено. Mежду "Character set"ами есть пробелы, в случае если найдётся дополнительный символ связанный с этим набором "Character set"ов, дабы не сдвигать номера соседних "Character set"ов понадобились пустые зарезервированные номера привязанные к определённым наборам "Character set"ов. Что же такое Unicode — это наборы практически всех знаков письменных языков "Character set«ов, предоставленных нам для использования в нумерованном представлении. Этот стандарт не единственный в своём роде, но он охватывает все предыдущие стандарты. Исторически сложилось так, что первые разработчики компьютеров были носителями английского языка, и разработка первой кодировки предоставлялась им. Она получила название ASCII (American Standard Code for Information Interchange), на этом всё не остановилось, и расширялось таким образом что бы собрать все кодировки вместе объединив их под одним стандартом Unicode. Большинство символов используемых в основных языках мира занимают 65 536 code points(к которым мы вернёмся позднее) и образуют Basic Multilingual Plane (BMP) (Основной Многоязычный Уровень). Оставшиеся (более миллиона) code points вполне достаточно для кодирования всех известных символов, включая малораспространенные языки и исторические знаки.Теперь давайте разберём что такое «Codeunit» ,"Codepoint" и «Codepoint» -это так называемое нумерованное положение в кодировке. Перейдём теперь к «Codeunit», и потом их совместим для детального рассмотрения. "Codeunit«- это тип хранения состояния для обработки в данный момент. Существуют, по крайней мере в моём представлении две формы «Codeunit» — это байты и символы. Почему я написал про состояние для обработки в данный момент давайте разберём детально. Мы работаем со строками в данном случае, можем воспользоваться для удобства "char«амии, но есть необходимость в форме с байтами, там где символы недопустимы. Например мы захотим передать символы функционалу который с символами не работает, а работает непосредственно с байтами по этой причине «Codeunit» может принимать различные формы. Так что же такое «Codeunit» — это форма представления символа по ключу"Codepoint«, в массиве ключей «Сoded character set». Теперь плавно перейдём к самим символам и разберём что такое «glyph» и «font». «Glyph» — это наша картинка, изображение нашего символа в каком то стиле, а «font» это разнообразные стили отображения "glyph«ов. Всё было бы хорошо, и не плодилось бы столько различных терминов, если бы все символы помещались в unsigned char. И в нашем случае породило ещё один термин называемый «supplementary characters» или суррогатные пары. Проблема заключается в том, как нам быть если мы вышли за максимальные рамки положительного "char«а. И так «supplementary characters» означает что несколько значений составляет один символ. В пример можно привести китайские иероглифы, в большинстве "Character set«ов имеются символы суррогатные пары, например в русском языке это «Ё», она состоит из E(0×0415) и двух точек(0×0308).Думаю нужно ещё отметить правила «Charset», по которым мы сможем получать из ключа "codepoint"а массив "Codeunit«ов, и наоборот но до этого нужно разобрать что представляют из себя формы кодирования. Стандарт UNICODE поддерживается тремя формами, (UTF-32), (UTF-16) и (UTF-8), плюс для и кодировки. Существует дополнительные способы кодирования, которые отличаемы приставками BE и LE. BE и LE расшифровываются как big-endian (BE), дословно «тупоконечный» — порядок байт от старшего к младшему, и little-endian (LE), дословно «остроконечный» — порядок байт от младшего к старшему. Начнем с (UTF-8) так как она практически везде устанавливается по умолчанию. Почему? Пока английский язык будит международным, и большинство текстов написано на нём, он будет самым употребляемым. Но есть маленькое но! — смотря с какими текстами мы будим работать, нам нужно выбирать подходящий для нас. Например если у нас только русский текст и его много, то стоит остановиться на Win — 1251. Например, если документ состоит только из символов ASCII (латинские буквы, цифры, знаки препинания и т. д.) — то в кодировке UTF — 8 символ будет занимать ровно столько же байтов, сколько в любой другой. Если документ содержит только буквы русского алфавита, и никаких других символов — то в UTF — 8, он действительно станет в два раза больше. А если в нём, например, поровну русских и арабских букв — в UTF — 8 он будет в два раза меньше, чем, например, в Win — 1251. Вот теперь можно перейти к другим кодировкам менее популярным. Далее появилась «UTF-16» почему 16 по причине расширения границ кодировки (2 в 16 степени) 65536 в отличии от «UTF-8» которая составляла (2 в 8 степени) 256. «UTF-32» В отличии от его старших но ростом не вышедших братьев которые используют переменное число битов для представления символов "Unicode«а, он использует все свои 32 бита для кодирования символов хотя это число не превышает 1м+. Преимущество его в доступе к символам занимающей одинаковое количество единиц времени, а недостаток — в размере четырёх байт на любой символ.
Думаю нужно отойти от терминологии, и перейти к ответам на вопросы по теме Ивана.
Почему строка в которой в два раза больше букв (2 вместо 1) занимает в только 1.5 раза больше места? По данному коду мы раскодили «A» в UTF-16, и мне нужно копнуть поглубже рассказав почему «A» в UTF-16 = 4, а «AА» в UTF-16 = 6. UTF-8 для хранения одного символа достаточно 1 байта, UTF-16 нужно 2 байта на символ, и UTF-32 как я выше говорил занимает максимальное количество байтов 4, возможно хранить и в 6 байтах значение символа, но они не включены в стандарт Юникода. Так по чему же 4 на один символ в UTF-16? Как я упоминал выше есть дополнительные BE и LE маркеры, и вот почему наш первый символ распух. Если мы указываем LE, то в начало нашего массива байтов записывается маркер последовательности байтов, который указывает что кодировка LE .Сейчас пойдём ещё глубже, и я напишу что такое big-endian и little-endian. И так BE это порядок байт от старшего к младшему, дословно можно перевести как «тупой конец» от старшего байта An. Ао к младшему, LE перевёртыш от младшего Aо . An к старшему. BE это как бы стандарт, его также называют «сетевым порядком байт». Так вот если мы не указываем что наша кодировка BE или LE, то в начале нашего массива байт будет маркер, соответствующий BE или LE. А если мы явно указали BE или LE, то этот маркер в наш массив не входит. И так UTF-8 был написан для работы с восьми битными символами, но в них нет ни Украинского, и нет Русского. В общем если мы не из ASCII, то будьте добры использовать не 1 байт, а размер от 2 до 6 байт. Но 6 байт как я говорил не используется, для суррогатных пар достаточно 4 байт.
Использование latin1, как заметил Mike Gorchak приводит к некорректному результату, лучше взять cp1251. Я думаю прочитав ответ выше всё будит понятно. Но дополним что такое cp1251 — эта кодировка содержит: русский украинский, белорусский, сербский, македонский болгарский, в общем это наш ответ ASCII.
А что такое этот самый «UTF», если «их» так много?UTF-8 [65] = «A» eng, это ASCII и оно помещается в 1 байт, и поэтому в консоли у нас число 65, который в свою очередь является кодом, буквы "А«eng. UTF-16 [-2, −1, 0, 65] = так как это UTF-16 то под символ мы задействуем 2 байта, на которые указывает 0(первые 8 бит) который не задействован в букве «А», и код той самой «A», остальные байты указывают нам на то, что мы не указали явно что это BE или LE.UTF-16BE [0, 65] = В данном случае, мы явно указали что это BE, значит «от старшего байта An. Ао к младшему».UTF-16LE [65, 0] = LE указывает на — «от младшего Ao. An к старшему»UTF-32 = мы занимаем 4 байта, для любого символа.UTF-32BE = «от старшего байта An. Ао к младшему».UTF-32LE = «от младшего Ao. An к старшему».
Как строка из одного символа может сохраняться в разные размеры байтовых массивов?Первый символ у нас 0×0001, и мы попали в неиспользуемые символы, но всё равно занимаем 1 байт. Второй символ 0×0111 указывает на символ «d» , но этот символ не является ASCII, это латинская «d» со штрихом(смотрел по таблице Unicode), по этой причине он выходит за рамки стандарта ASCII, и как я оговаривал выше должен занимать от 2 байт. Третий символ 0×1111, он уже занимает 3 байта и называется Hangul choseong phieuph.
Давайте разберем детальнее:Начнём с 1 байтного символа, он выглядит как — (0xxx xxxx). Первые 2 бита нам указывают на то, что это конечный символ. Если первый байт выглядит как — (110x xxxx), то это не полный код символа, а только первая часть на что нам указывает «110», а вот вторая часть (10хх хххх). 10 нам говорит о том, что это только часть одного символа. Так вот в нашем третьем случае этот байтный массив выглядит примерно так — (1110 хххх, 10хх хххх, 10хх хххх).
Последний вопрос, который мы также рассматривали на лекции в самом начале звучит так: Все таки в этой строке ОДИН символ или ДВА?И ответ на данный вопрос — один символ, потому что это суррогатная пара, и состоит она из двух символов, но эти символы нелегалы. Нелегальны они по причине того, что отдельные части этого символа не несут полезной информации, кроме той, что символу нужна ещё одна недостающая часть.