Pull to refresh

Comments 118

Сел я тут читать книгу «Thinking in Java» (4-ое издание). И вот что в этой книге пишут в главе 2, подраздел «Список аргументов»:

"…
int storage(String s){
	return s.length() * 2;
}


Метод указывает, сколько байтов потребуется для хранения данных определенной строки. (Строки состоят из символов char, размер которых — 16 бит, или 2 байта; это сделано для поддержки набора символов Unicode.)..."

Я новичек в Java и понятия не имею как на самом деле там хранятся символы и строки. Но давайте отвлечемся от Java и ответим на вопрос в заголовке безотносительно языка программирования — сколько, по-вашему, занимает 1 символ в кодировке UTF-16, согласно её спецификации? И давайте сначала ответим, как думается, а потом полезем смотреть верный ответ в Гугл и Википедию.
UTF-16 никакого отношения к яве не имеет. Строки хранятся в виде массива char'ов в UCS-2 (в неправославном big endian'е, как и всё остальное, к сожалению).
Я не знаю, какой язык использует нативно UCS-2 вместо UTF-16.
Изначально ява использовала UCS-2, позже перешли на UTF-16.
String состоит не из букв, а code points строго говоря. Поэтому в книге пишут только про 2 байта, а не 2-4 как UTF-16.
В UTF-16 — строго 16 бит на каждый символ, вот в UTF-8 от одного байта до четырёх.
По крайней мере, если я правильно помню…
Не уточнили видимый символ или просто символ? Если видимый то может сколько угодно от двух. А вот если просто так сказать самая малая не делимая единица (переносы строк, ударения, буквы, другие модификаторы букв) то 2.
С каких пор можно делить суррогатные пары?
Я думаю что комментатор имел ввиду, что, например, буква A + combining diaresis — это два кодпоинта, но один character. Поэтому один character может состоять из произвольного количества кодпоинтов.

только до шести, но по факту до 4-х, остальное не используется пока
Не. По стандарту, 1-4.
А как оно задумывалось изначально никого уже не волнует.
По-моему очевидно.
Заглянул в стандарт — ISO/IEC 10646:2011(E).
Как ни странно, но совпало с педивикией :)
Скрытый текст
9.2 UTF-16
UTF-16 is the UCS encoding form that assigns each UCS scalar value to a sequence of one to two unsigned
16-bit code units, as specified in table 4.
Я думал неограниченно… :( Правда на практике никогда не сталкивался
Не могу найти в этом тексте слова «символ» :)
Есть такое.
Я про code point'ы подумал.
Я не знаю что в Unicode назвать символом.
Точнее знаю, но там 2 или 3 варианта.
Символом юникод называет coded character (подробности тут). Между прочим, не каждый код поинт это coded character, хотя обратное утверждение верно. Но вне контекста стандарта символом называют все что угодно, что вполне легитимно, потому что юникоду ни кто не давал права переопределять лингвистические термины всех языков мира.
Если я правильно понял Википедию, правильный ответ не 2-4, а именно 2 или 4 байта, т.е. 3-байтного символа в кодировке UTF-16 быть не может.
Там показано с учетом кодирования в Quoted Printable и Base64.
Правильный ответ 2-4.
Утверждение: «Каждый символ в UTF-16 занимает 2 или 3 или 4 байта», — верно.
Приведите-ка мне пример с 3 байтами.
Прям значения байтов и что должно получиться.
Вы правда не понимаете, что утверждения:
«Каждый символ в UTF-16 занимает 2 или 3 или 4 байта»
«Символ в UTF-16 не может занимать 3 байта»
верны оба?

Если нет, то приведите мне пример UTF-16 символа, который будет занимать количество байт, отличное от «2 или 3 или 4».
Ладно, в таком случае сойдемся на «любая кодовая точка в UTF-16 представима в виде 1 или 2 или 3 или 4 или 5 или 6 или 7 или 8 или 9 или 10 или 11 или черт знает скольки байт». В любом случае, выражение будет true. Вы на это намекаете?

Верное утверждение это — любая кодовая точка в UTF-16 представима в виде 2 байт или 4, при использовании суррогатной пары, для кодовых точек не из BMP.

Вот это наиболее полный ответ (возможно, без учета каких-то 7ми байтных систем)
Полностью с вами согласен. Я не тверждал, что символ в UTF-16 может быть 3-х байтным. Я лишь говорил, что в той формулировке, в которой сформулирован вопрос и ответы, правильный ответ «2-4».
Сорри за масло масляное и очепятки
Ну а я считаю, что так можно на любой вопрос в мире о количестве тогда отвеачть — «любое натуральное число».

Короче, имхо, правильный ответ — «правильного ответа выше нет».
А суть вопроса была в том, чтобы каждый увидел знакомое число и ответил, а не подумал головой.
Забавно, что правильный ответ — последний :) Он же всего лишь второй по полуряности.
Учитывая статистику, многие также и не знают сколько занимает UTF-8. Уж программисты и веб-разработчики должны-то знать.
Не сочтите за призыв к невежеству, но имхо среднестатистическому веб-разработчику это знать не так уж и необходимо.

PS: Сам выбрал «кажется верный» вариант (2-4 байта)
Так уж случилось, что Хабр наполнен не одними лишь веб-разработчиками.
Ответил 2-4. Жду оглашения правильного результата.
P.S.
Работать с UTF-16 не приходилось, выбирал следуя внутреннему пониманию стандарта )
Неправильно же. 2 или 4. А 2-4 это вомзожно и 3. А там или 2 байта, или если суррогатная пара (о которых все стараются забыть и напрасно) то 4.
Знал ответ… но только потому что изучил этот вопрос при изучении json
Результаты напоминают о топике.
В том смысле, что на не-жизненно-важный вопрос люди отвечают первое, что покажется похожим на истину.
А вообще, это знать никому нафиг не нужно покуда своя программа не завязана на работу с этой кодировкой.
Во многих программах, связанных с шифрованием, ручной сериализацией, обменом данными по сети это может пригодиться. При реверс-инжиниринге. А я вот столкнулся с этим в вообще неожиданном месте — когда писал парсер ID3 тегов в mp3-файлах (текстовые теги тоже могут быть в UTF-16, при чём еще и с разным порядком байт)
Не спорю, и сам сталкивался как-то, вам читать начиная со слова «покуда».
Один Unicode Endpoint в кодировке UTF-16 занимает 2 или 4 байта (в зависимости от того, входит ли этот endpoint в BMP (Basic Multilingual Plane), или нет).

Самая же интересная часть вопроса в том, что такое «символ».

Если для упрощения символом считать один endpoint, то он занимает 2 или 4 байта.

Но символ как отдельностоящий графический элемент может состоять из несколько endpoint'ов и иметь несколько вариантов записи в виде последовательности unicode endpoint'ов. Например, символ «й» можно представить двумя способами:
1) U+0439 CYRILLIC SMALL LETTER SHORT I
2) U+0438 CYRILLIC SMALL LETTER I; U+0306 COMBINING BREVE
Не все используемые комбинации имеют представление в виде одного код поинта. Большинство как раз не имеют. Даже в Русском, например, возьмем ударение U+0301 combining acute accent, в юникоде нет сочетания его ни с одной другой буквой кириллицы. А о других языках я и не говорю.
Блин, на автомате подумал, что речь идёт о UTF-8, так как только с ней в основном и имею дело, и ответил как для неё.
UTF подразумевает virable lengh, UTF-8 подразумевает 8 бит и больше, очевидно (по аналогии) UTF-16 от 2 и более. До бесконечности он вряд ли, так что ответ 2-4.

Хотя смысл этого мне не понятен, т.к. в UTF8 — от 1 до 6, так что никакого специального выигрыша не наблюдается.
Смысл в том, чтобы обеспечить обратную совместимость при переходе с UCS-2.
Я предпочитаю совместимость с ASCII, так что оставьте лучше UTF-8. А что такое UCS-2 мне пришлось гуглить — и нафиг оно такое сдалось?
Тащемта UCS-2 и был фактически синонимом юникода до появления UTF. В частности в NT применялся UCS-2, так что кроме UTF-16 ни как бы не получилось перейти к расширенному юникоду, сохранив совместимость.
Это не проблема MS, я же говорю — изначально UCS-2 был единственным вариантом юникода! -_-
Потом юникод расширили (16 бит стало не хватать) — UCS-2 объявили устаревшим, придумали UTF.
Там где представление символа не имеет значение (например, в перле), спокойно перешли на UTF-8. Если же представление символа важно (в яве char по стандарту — 16 бит, WCHAR в винапи — тоже), пришлось использовать UTF-16.
UFO landed and left these words here
Не все UTF* является кодировками с переменной длиной; например в UTF-32 каждый endpoint всегда занимает 4 байта.
Ну тут правильно начали про дополнительные символы (типа ударения, или палочки над й замечать) — тогда «символ» как «глиф» от 2 до бесконечности. А вообще 1 кодовая точка задается или 2 байтами или 4, если суррогатная пара, которая используется для представления точек не из BMP
Под длиной символа для юникода (в приложении к обработке в приложениях) традиционно подразумевают минимально различимый элемент. Условно говоря, «на каком месте можно безопасно резать byte-sequence, чтобы получить две парсябельные unicode-строчки».
Удачи с отображением пользователю если разрежете строку посреди комбинирующей последовательности.
«на каком месте можно безопасно резать byte-sequence, чтобы получить две парсябельные unicode-строчки»—это grapheme cluster. А они могут быть произвольной длины.
UTF-32 можно. А что 16 бит на юникод не достаточно, это известно, значит переменное.
Вы слишком категоричны. Лично я недоумевая только ответившим «1 байт» и «16 байт» — это что же в голове должно твориться, чтобы такое ответить? Остальные позиции более-менее аргументированы, а цель поста — просто показать что самое распространённое мнение «ровно 2 байта» не верно. Надеюсь, у меня получилось.
Я ответил 4, и это учитывая то что я что-то там еще считал =)
Я когда вижу «UTF», то сразу думаю, что число байт переменное, но 2-4 мне показалось маловато…
Неужели вы никогда не разбирались с UTF перед работой со строками c# и java?
Да и 4 байта это 4 миллиарда комбинаций, куда больше-то. Сейчас занято всего 0x10FFFF
Где-то слышал, что непосредственно код символа в Юникоде занимает 4 байта, знаю принцип согласно которому код символа Юникода кодируется в UTF-8 путём использования старших бит в байтах для служебных целей (определения длины символов), а некоторые комбинации недопустимы в принципе, из чего делаю вывод, что для представления символов символов Юникода (4 байта) в кодировках типа UTF (служебные биты и в принципе недопустимые байты) 4 байт не хватит, если не делать предположения, что код символа Юникод хоть и кодируется 4 байта, но не использует все 32 бита.

Плюс ещё смутные представления о том, что один печатаемый символ (условно — буква реального алвафита) может кодироваться несколькими символами Юникода (например, базовая буква и диакритический знак), то есть даже если считать что все символы Юникода кодируются двумя байтами (то есть 16-бит словом или 65536 символов), то для кодирования реального символа какого-то языка может потребоваться два полноценных 16-бит слова, то есть 4 байт. А зная что символов в Юникод заведомо больше 65536, прихожу к выводу, что для кодирования произвольного реального символа 4 байт будет мало — больше двух байт на основной символ и больше двух байт на диакритический знак, если не делать предположения, что основные символы и диакритические знаки искусственно помещены в область где точно хватает двух байт (и индикацию того, что двух байт хватает).

Как-то так.

Возможно, это связано с тем что только что разглядывал таблицы соответствия количества символов в строке занимаемому месту для различных типов в mysql
Я даже знаю, почему. Многие обращают внимание на цифру 16 :)
Смотря в какой системе исчеслений.
В девятнадцатиричной системе исчисления «шестнадцать» будет цифрой. Просто обозначаться эта цифра будет, скорее всего, каким-то другим символом.
Не-а. «16» в девятнадцатиричной системе счисления всё равно будет не цифрой, а числом, только равным не 1610, а 2510.

А то, что написал ув. Keyten — это число, с точки зрения содержания, и две цифры, с точки зрения формы. Придираюсь, конечно, но почему бы и нет? Никому же не обидно, надеюсь.
Хм, а с чего Вы решили, что «16» в девятнадцатеричной системе будет числом? Может быть
, Shultc, как автор вот этой самой новопровозглашенной девятнадцатеричной системы скажет использовать для обозначения десятичной цифры «5» — букву «Ы», а для какой-то другой цифры — графическое обозначение «16» — как один символ.
Благодарю вас. Вы уловили суть того, что я пытался донести. Хотя, разумеется, изначальное замечание torbasow'а было верным.
Какая разница? Число есть число, как бы оно не записывалось, хоть последовательностью пробелов, хоть импрессионистским рисунком. Вы опять путаете числа и цифры. Цифры — это символы, которыми записываются числа. И цифрой будет любой такой символ, независимо от того, чем он является в другом контексте.
Да, цифры — это символы, которыми записываются числа. И вот в этой девятнадцатеричной системе у меня будет символ «16», который обозначает, к примеру, десятичное «3». Почему нет?
Вот! Вот это можно в какой-то системе счисления и цифрой назвать.
Т.е. Вас смущало, что там это было два символа, а тут один? А если и то и то написать от руки на бумажке — в чём разница?
О, кстати по теме… На самом деле, и к ‘16’ можно относиться как к одному символу (user-perceived character), в каком ни будь контексте. Юникод это признаёт. Конкретный пример: ‘ch’ считается одним символом в чешском и словацком, а не двумя. Вот поэтому вопрос в топике и не корректен. Что такое символ? Code unit? Code point? Grapheme cluster? User-perceived character?
В зависимости от контекста, как Вы правильно заметили.
Меня ничего не смущало. Просто это были две цифры по форме или одно число по содержанию. Не «цифра». В умолчательной десятичной системе счисления. В какой-то другой системе счисления можно цифрой считать хоть три зелёных свистка, хоть что угодно, но тут была десятичная, записанная обычными арабскими цифрами.
Э-э! Вы в начале утверждали, что (цитирую): «Я думаю, в любой» — а теперь уже «В зависимости от контекста», при чём обуждение началось с девятнадцатеричной системы. Вот на счёт контекста, это верно, а «в любой» — нет.
Какая разница? Дело не в этом, а в том, что на 16 обращают внимание. А 16 бит — это 2 байта, между прочим.
Великолепный опрос. С печальными результатами…

Ответил «2-4», но, вероятно, правильнее было бы выбрать «другой ответ», потому что в 2-4 и 3 входит, что, разумеется, неверно.
Грустный смайлик в конце заголовка опроса согласен с вами, что печальные ):
Интересно, а как много народа с ходу скажет, сколько байт занимает символ в моей локали (кои8-р)? ☺
Кэп подсказывает символ кои8 занимает 8 бит :3
> в моей локали (кои8-р)
да вы, батенька, эстет :)
UFO landed and left these words here
uname -srv
Linux 3.4-pf #1 SMP PREEMPT Mon Jun 18 01:32:47 EEST 2012
давайте договоримся, что байты зелёного цвета — тогда это не принципиально
я лошара :) :( раз уж в utf-8 4 байта, так в utf-16 должно быть 8 байтов :D и логично правильного ответа нет
Страшно представить сколько же места на диске будет занимать текст в UTF-32.
Про UTF-256 я вообще молчу.
Ответ на этот и многие другие вопросы связаные с кодировками — www.utf8everywhere.org
Там подробно объяснено приемущество UTF-8 над UTF-16

А вот ссылка на мифы про количество байт в UTF-16:
www.utf8everywhere.org/#myths
Автор, я не понял, имеется в виду символ или code point?
Колебался между 2-4 (так как 3 входит) и последним — чувствовал подвох. :)
Выбрал 2-4, но никак не ожидал, что эти два ответа не войдут даже в тройку лидеров…
Если символ в первых таблицах — то 2 байта (16 бит), если не в первых — то минимум 2 ( и дальше 4-6-8+ в потенциале байт).
На деле не больше 4х (Помоему даже все китайско-японско-корейские входят помещаются в 4 байта).
Ответ 2+, «прыжками» в 2 байта (2/4/6...)

UTF8 добавляет 8бит для каждого символа (если ему не хватает предыдущих), UTF16 — прыжками по 16.

Выбрал 2-4, как наиболее подходящий.
Всем рекомендую почитать статью Спольски про кодировки "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)" (англ.), она хотя и древняя, но до сих пор актуальна.
На русском точно знаю, что есть в книжке "Джоэл о программировании".
Так какой в итоге правильный ответ?
Правильный ответ в том, что «верного ответа нет».
Можно утверждать только, что в UTF-16 один code point Юникода можно закодировать одним или двумя 16-битными словами. Остальное — зависит от прочих условий.
Некорректный вопрос (и, соответственно, ответы), похоже только 351 (последний ответ) + 614 (предпоследний ответ) человек на хабре на данный момент знакомы с юникодом. :)

Нужно различать юникодовские [abstract] character (символ), symbol (графический спецсимвол), character code point (собственно, минимальная единица юникода), glyph (глиф). В связи с переполненностью смыслами значений слов «символ», а также с тем, что мне русская версия ISO-10646 и, как следствие, официальная терминология неизвестна, сама формулировка опроса слишком расплывчата.

Когда речь идёт о Юникоде и когда последнее критично, нужно всегда уточнять терминологию, что бы понимать проблему — противное чревато проблемами, в т.ч. с безопасностью.

По теме: насколько я знаю, количество комбинирующих символов не лимитировано, т.е. по смыслу верный предпоследний вариант, но без уточнения терминологии этого утверждать нельзя:

Стандарт: «2.11… In the Unicode Standard, all sequences of character codes are permitted.… This does not create an obligation on implementations to support all possible combinations
equally well. Thus, while application of an Arabic annotation mark to a Han character
or a Devanagari consonant is permitted, it is unlikely to be supported well in rendering
or to make much sense.»
UFO landed and left these words here
UFO landed and left these words here
На чем вы основывали суждение о своей правоте?
я ответил 2, хотя правельный вариант был 2-4. Мне не капли не стыдно. Я к примеру до сих по не знаю чем отличается абстрактный класс от интерфейса:) кто читал предыдущие посты шутку поймут!
Насколько я знаю, два (базовая плоскость) или четыре (суррогатная пара).
Sign up to leave a comment.

Articles