Здравствуйте, меня зовут Дмитрий Карловский и я... серийный убийца устоявшихся стандартов. Сегодня я выследил и нанёс критический урон UTF-8. И сейчас я расскажу, как я его переиграл и уничтожил новым стандартом кодирования текста — Unicode Compact Format.

Древний Вавилон
Сначала был 7-битный ASCII и все телетайпы понимали друг друга. И было это хорошо. Но никто не хотел учить английский язык или транслитерировать родной — все хотели говорить на своём. Благо в байте не 7 бит, а 8, а это значит, что туда можно всунуть много самых правильных букв.
И расплодились тогда 100500 кодировок: под каждый язык свои коды букв, а под каждую кодировку свой шрифт. И даже под один язык было более 9000 кодировок: от KOI8-R и CP-866, до Win-1251 и ISO-8859-5. Это привело к самозарождению крякозябр - адовых монстров, съедающих наши любовные послания, и оставляющих вместо них сами знаете что.
В этом свете, невозможность использовать в одном тексте слова на разных языках, была не более чем мелкой букашкой. Не приятно, ну и ладно — наш деды же как-то выжили без этой фичи!
Lingua Franca
И собрались умные мужи со всего мира. И решили они создать единый код, чтобы править всеми. И назвали они его — Юникод.
И появился у каждой буквы свой глобально уникальный номер. И жили мы с тех пор дол... да кого я обманываю — мужи эти быстро поняли, что на все комбинации букв и диактрики никаких кодов не напасёшься, поэтому имеем мы теперь много разных вариантов записи одной буквы, и несколько алгоритмов нормализации текста: NFD, NFC, NFKD, NFKC, KFC.
А чтобы жизнь раем не казалась, придумали они ещё и пачку кодировок:
Двух байтовые: UCS-2 фиксированной ширины и UTF-16 — переменной.
Четырёх байтовые: UCS-4 фиксированной ширины и UTF-32 — переменной.
Происходило же это всё и в разгар битвы тупоконечников с остроязычниками, так что каждая многобайтовая кодировка обзавелась ещё и двумя вариациями с разным порядком байт. А чтобы не запутаться в этом дикообразии, к ним во фронтальную проекцию прикрутили опциональный BOM.
А тут на сцену выходят китайцы, и достают из широких штанин свой GB-18030. Да вы, блин, издеваетесь!
В конце должен остаться только один
В таблице символов Юникода чуть более миллиона позиций, для кодирования которых хватило бы и 20 бит (что не более 3 байт). Но большая часть из них до сих пор не используется, так что пару бит можно смело выкидывать на мороз.
Ещё пара бит тратится на всякую никому не очень нужную экзотику. Так что если очень постараться, можно было бы упаковать все реально используемые письменности в 2 байта, не захламляя Юникод всевозможными картинками. Я вот всё жду, когда же туда начнут добавлять фотки известных личностей — вот тогда-то заживём! Тогда-то и пригодятся зарезервированные 640K значений в середине таблицы...
В этом свете 4-байтовые кодировки выглядят крайне избыточно. Поэтому их никто и не использует. Двухбайтовый UCS же очень удобен в работе, но доминирующий в IT английский текст, раздувается в ней двукратно.
Да и набор из 64К символов в какой-то момент стал всем жать, из-за чего появились костыли в виде суррогатных пар, руинящих все достоинства двухбайтовых кодировок. Но до сих пор многие рантаймы работают с UTF-16 строками в режиме UCS-2 в виде двухбайтовых массивов, то и дело выдавая WTF на суррогатных парах.
Более поздние языки и форматы уже безальтернативно прибили себя за яйца гвоздями к UTF-8, дающему 1 байт на символ для латиницы, 2 — для кирилицы, 3 — для китаицы, и 4 — для урожицы. Упоротый же UTF-1 с кодированием по модулю 160 и запрещённый UTF-7, который авторы наивно хотели использовать в протоколах без экранирования, так и не обрели популярность, поэтому их просто скипаем.
Звездолёты в большом театре
Англосаксы счастливы — у них каждый символ помещается в 1 байт. Но весь остальной мир, в котором на символ нужно минимум 2 байта, даже если он выглядит идентично латинице, тихо завидует и не находит себе места.
UTF-8 довольно простой, если не считать приколов с суррогатными парами, добравшимися и до него. Но добрую треть всех бит он тратит впустую во имя самосинхронизации, вместо того, чтобы потратить их на коды коррекции ошибок. Иначе говоря, решать вопрос битых данных надо не на уровне кодирования текста, а на транспортном уровне, чтобы он гарантировал точную доставку, любых данных. Даже не текстовых.
Так что появление кодировок без этого легаси, было лишь вопросом времени:
SCSU — это расширенная ASCII кодировка, где управляющие коды позволяют переключаться между семибитными однобайтовыми окнами и UTF-16-BE. При этом печатные ASCII символы всегда представляются одним байтом как есть, без переключения режимов.
Для работы с ней требуется куча таблиц и сложные алгоритмы, выбирающие самое компактное представление из нескольких возможных, что не только снижает производительность, но даёт ещё и недетерминированность бинарного представления одних и тех же символов.
BOCU-1 использует разностное кодирование переменной длины по модулю 243. Не смотря на относительную простоту и детерминированность, использование модулей не кратных 2, снижает производительность, так как вместо битовых операций приходится использовать дорогостоящие деления и умножения.
Но что ни сделаешь ради компактности... ведь расстояние между буквами, например, в русском языке не превышает 128, что позволяет уложиться в 1 байт на букву. Но кто же мог подумать, что любой знак препинания или цифра — это уже двухбайтовый прыжок до ASCII и такой же потом обратно? Хорошо хоть для пробела оставили костыль в виде абсолютного однобайтового значения, не влияющего на смещения.
UTF-C — тут товарищ начал за здравие с минимизацией служебных бит, а кончил как обычно: звездолёт с перекодированием таблицы символов под себя, и жонглированием кодов между основной страницей и дополнительной. Пожелаем же ему успехов в ручном переупорядочивании сотен тысяч символов Юникода и дальнейшей поддержке этого форка.
Итого: проблема компактного представления остаётся, а все её решения одно лечат, а другое калечат.
Да придёт спаситель
И тут на сцену выхожу я. Пиво я не пью, так что без долгий прелюдий начинаю отжигать, изобретая Unicode Compact Format...
Для большинства языков хватило бы и 1 байта на символ. Но таких языков много, а в байт помещается всего 256 значений. Следовательно, нам никуда не уйти от "режимов" соответствующим разным письменностям.
Так как символы из разных языков могут смешиваться как угодно, то переключение режима должно иметь минимальный размер и укладываться в 1 байт. Соответственно, число возможных режимов сильно ограничено, деля свои коды с кодами символов.
Таблица Юникод предусмотрительно выровнена по блокам из 128 значений, где самый первый блок идентичен ASCII для совместимости с ним. Отлично, будем использовать эти блоки как узкие станицы. Одним байтом переключились на нужную страницу и далее в рамках этой страницы каждый байт со значением до 128 — один символ. В наихудшем случае будет 2 байта на символ.

Появление байта со значением от 128 уже включает UCF расширения. 100 значений необходимо и достаточно, чтобы покрыть почти все письменности с компактными алфавитами, включая японскую Кану. А это суммарно диапазон в 12_800 символов от начала.
Ещё минимум 4 значения нужно для переключения на широкие страницы, где каждый символ кодируется 2 байтами. В каждую такую страницу влезает 32K значений (половина от первого байта и целиком второй). Этот режим актуален для иероглифического письма типа китайского или зумерского эмодзи.
Если отсчитывать широкие страницы от 0 символа, то базовый набор китайских иероглифов режется между двумя разными страницами, что может приводить к постоянным переключениям режимов. Однако, первый десяток тысяч символов мы уже кодируем узкими страницами, так что смещаем отсчёт широких страниц на 8К и вся китайщина влезает в первую страницу. Voilà!
Кстати, да, французам с диактрикой и украинцам с их Ґ мы помочь не сможем — придётся им переключаться между страницами, что в худшем случае выливается в 3 байта на одиноко стоящий такой символ вместо 2 у UTF-8. Можно было бы, конечно, всё переусложнить и накостылять что-то для одних языков, ценой ухудшения других, но мы такой ерундой страдать не будем. Хотя... может у вас есть светлые идеи на этот счёт?
Однако, заметим, что во всех языках есть включения тех или иных ASCII символов, а значит они должны быть по возможности доступны одним байтом без переключения режима. У нас осталось максимум 23 значения для цифр и базовой ASCII пунктуации, для которых всё же заведём табличку.
Ах, да, осталось ещё 1 значение, которое зарезервируем за переключением в 3-байтовый режим, позволяющий закодировать в 8 раз больше символов, чем вся таблица Юникода, большая часть которой на текущий момент вообще пуста. Нужен он нам лишь на всякий случай, чтобы не не терять данные и не кидать исключения на совсем экзотических кодах, которые в реальных текстах встретятся примерно никогда.
Мексиканская дуэль
Взглянув на референсную реализацию на TS вы можете заметить, что UCF так же прост, как и UTF-8, но при этом в 1.5-2 раза компактнее для почти всех языков:
Английский текст в UCF и в UTF-8 представляется одинаково — как ASCII.
Русский текст в UCF почти в 2 раза компактней, чем в UTF-8.
Китайский — почти в 1.5 раза.
Эмодзи — почти в 2 раза.
По скорости работы UCF и UTF-8 в Chrome примерно одинаковы, если не считать, что нативный UTF-8 энкодер в V8 — редкостный тормоз, поэтому я и запилил свой:


Сравнение с SCSU, BOCU-1 и UTF-C оставлю вам в качестве домашнего задания. По этим данным сжимают они примерно так же, а работают медленнее. Если потребуется, моя либа доступна не только в экосистеме MAM, но и в NPM.
И в чём я не прав?
Я много над всем этим думал (целую неделю), перепробовал кучу вариантов, игрался с константами, списывал у соседей, но пришёл к тому, что вы сейчас видите. Понятное дело, что никто не побежит сейчас внедрять этот формат в свои проекты, протоколы, языки. Ведь всё уже устоялось, и вообще наступил конец истории.
Однако, видя не совершенство мира, я не могу устоять от соблазна сделать его чуточку лучше. Поэтому я планирую внедрить UCF в свой формат бинаризации произвольных данных VaryPack, который используется в моей децентрализованной базе реального времени Giper Baza, у которой есть все задатки стать основой Web4. И совершенно не хочется тянуть легаси в будущее, в то время как есть возможность всё исправить, и не мучать наших правнуков призраками прошлого.
Но я всего-лишь человек с двумя глазами и двумя полушариями. Я могу что-то не заметить, до чего-то не догадаться. Поэтому я публикую эту статью в надежде, что вы поможете подсветить все возможные косяки или подкинуть интересных идей, пока яйца веба будущего ещё свободны.
Если вам интересна вся эта движуха, то присоединяйтесь к нашему ламповому сообществу самых заряженных разрабов Гипер Дев, а то и поддержите нас рублём. Чем нас больше, и чем мы активнее, тем большие горы мы сможем свернуть вместе. Не ссыте, прорвёмся!
Комментарии (125)

Dmitry_Dor
05.01.2026 16:35¯\_(ツ)_/¯

/dejavu

nin-jin Автор
05.01.2026 16:35Одни и те же мемы из раза в раз. Вот нет бы что-то новое придумать уже.


kryvichh
05.01.2026 16:35Непонятно, какую задачу решает предложенный формат. Если компактизация текстовых данных для передачи, то можно использовать форматы ZIP или 7Z. Если известен язык текста и нужно ещё сильнее сжать, можно предварительно преобразовать в нужную ANSI-кодировку, и потом 7Z.
Человечество прошло этот этап, и лучше и универсальнее Unicode для обработки текста всё равно не придумать. Хотя вот LLM'ки кормят не буквами, а токенами - вот тут есть простор для оптимизации кодировки под разные языки и применения.

nin-jin Автор
05.01.2026 16:35Нет цели сжать любой ценой. Есть цель бинаризовать так, чтобы сжатие потом не требовалось. К тому же ZIP мало того, что существенно медленнее и сложнее, так ещё и ничего не даст на множестве коротких текстов. А Unicode вроде никто не отменял пока
кроме китайцев.
michael_v89
05.01.2026 16:35Есть цель бинаризовать так, чтобы сжатие потом не требовалось.
https://habr.com/kek/v2/articles/?period=daily&sort=date&fl=en%2Cru&hl=ru&page=1&perPage=10
Size 41 Кб
Transferred 10.70 КбЯ взял этот текст, перевел в UCF и сжал ZIP.
Text length: 41109 UCF length: 33605 Text gzip level 3: 10471 UCF gzip level 3: 9322 Text gzip level 9: 10022 UCF gzip level 9: 9120Даже в вашей кодировке сжатие все равно дает значительное уменьшение размера. То есть свою цель вы не достигли.
На 3 уровне сжатия получилась разница 1149 байт, на 9 уровне 902 байта. Для сжатого размера разница 10 процентов.
А одна вот эта картинка занимает 66617 байт. Даже по сравнению с ней разница загружаемых данных получается около 1 процента. А если все картинки посчитать, то еще меньше.

Garemoko
05.01.2026 16:35С вашим подходом не получится символ из потока считать произвольно, нужно будет пройтись по потоку обратно (если есть такая возможность), чтобы найти, к какой таблице он относится. А если часть данных повреждена — внезапно весь текст становится нечитаемым, придётся перебирать все таблицы, проверяя его на осмысленность. Вы именно алгоритм сжатия придумали, и у него есть свои минусы.

ss-pol
05.01.2026 16:35полностью поддерживаю, но есть много идей по улучшению, сам над этим размышлял, но не оформлял и не записывал
> Так как символы из разных языков могут смешиваться как угодно, то переключение режима должно иметь минимальный размер и укладываться в 1 байт. Соответственно, число возможных режимов сильно ограничено, деля свои коды с кодами символов.
Это сразу неправильно, наш идеологически выверенный православный юникод должен быть спроектирован так, чтобы число возможных режимов и число возможных символов можно было расширять без ограничений и противоречий, сохраняя совместимость. Программа, не знакомая с какой-то подкодировкой может её просто отобразить какими-то кубиками, но продолжить декодирование строки дальше.
Единственное о чём следует договориться, это что в начале идёт код подкодировки, который должен быть переменной длины. Этот номер подкодировки кодируется в стиле varint, то есть значения до 128 помещаются в 1 байт, от 128 до 16K - в 2 байта и т.п. Таким образом мы можем всегда добавить ещё одну подкодировку. Ещё в номере можно зарезервировать один бит для различения 0-терминируемых строк и строк с длиной строки, может ещё один для чего-то другого. Соответственно, самый популярные кодировки будут занимать 1 байт, менее популярные и более поздние -2 байта, а когда-то может дойдём и до 4х.Нуль-терминируемые строки используют 0 как индикатор переключения кодировки и два 0 (00) для индикации конца строки. За 0 всегда следует либо 0 (конец строки), либо код подкодировки, которая может быть и однобайтовой и двухбайтовой и в принципе какой угодно.
При этом подходе мы можем допустить строки и без 0-терминации, с длиной строки в начале. За это может отвечать один бит в номере кодировки.
Дополнительно можно в некоторых случаях обязать повторять подкодировку после символа перевода строки и/или точки. Это может быть полезно при чтении больших файлов.
Например, английский текст будет вполне читабелен любым latin1- или юникод- просмотрщиком, но будет иметь в начале пару "мусорных" байт.
При этом важно выделить страницу для каждого языка, чтобы мы знали не только кодировку, но и язык подстроки.Можно и сам utf-8 иметь в виде подкодировки при этом подходе.

nin-jin Автор
05.01.2026 16:35Необходимость поддерживать тысячи кодировок - капитально усложнит и замедлит реализацию без особого выигрыша в размере.

ss-pol
05.01.2026 16:35Выигрыш примерно такой же, как у автора - в 2 раза для кириллицы, например. Но по-моему основной недостаток юникода, на мой взгляд, не в избыточности, а в том что он не предоставляет информацию о языке. То есть кириллический текст, например, может быть русским, болгарским, украинским. Латинский - английским, немецким, итальянский и т.п.
Это неверно и является основным недостатком юникода. Важна информация о языке!

ss-pol
05.01.2026 16:35Важно оставить систему открытой для расширения в будущем. Одного байта будет мало даже на сегодняшний день.
> Согласно данным крупнейшего в мире каталога языков Ethnologue, по состоянию на 2024 год на Земле насчитывается 7164 языка
https://ru.wikipedia.org/wiki/Языки_мира
И языки не стоят на месте, будут развиваться. Если кодировать язык в строке (а это правильно и полезно), то одним байтом уже сегодня не обойдёшься. А в будущем их будет больше.
Это же относится и к самим языкам - они развиваются и меняются и неизбежно алфавиты будут меняться.

st---v
05.01.2026 16:35"Благо в байте не 7 бит, а 8".
ну в те времена, а точнее до 70х, в байте не всегда было 8 бит. были и 6-ти битные байты (IBM 704, PDP‑1) и 7ми битные.
yarkov
05.01.2026 16:35А в военное время количество байтов доходило до 9

pae174
05.01.2026 16:35В обычных байтах по 8 бит, но в каждом четвертом байте - 9. Потому что каждый четвертый байт - високосный.

Metotron0
05.01.2026 16:35Это юлианские байты

pae174
05.01.2026 16:35Ненене, это как раз григорианские байты на самом деле. С григорианскими байтами все просто - каждый четвертый високосный.
С юлианскими байтами немного сложнее:
В первых 36 юлианских байтах високосными являются каждый третий байт. Но первый юлианский байт сразу високосный (но это не точно - см. ниже).
Потом следующие 16 байт - все подряд невисокосные.
И только начиная с 52 байта високосными являются каждый четвертый.
Причем существует две реализации юлианских байтов - в одной отсчет високосных байтов начинается с первого байта, а в другой - со второго. Точнее, реализаций на самом деле больше двух, но эти две наиболее распространены. Реализации несовместимы между собой, однако по причине наступления EOL для них всех это уже не имеет никакого значения.
Стандарт на размер юлианских байтов оказался слишком сложен в реализации и поэтому продержался совсем недолго - всего каких-то 1600 лет - и был заменен григорианскими байтами. В процессе замены 11 байт были безвозвратно потеряны, но так как это случилось больше 400 лет назад, то их уже не спасти. И бэкапов нет. Ну или нам всем врут, что их якобы нет.
То есть я понимаю, что это звучит дико, но тем не менее.

Metotron0
05.01.2026 16:35Но ведь в григорианских, если номер байта делится на 100, то он не високосный, кроме случая, когда он делится ещё и на 400.

Flammmable
05.01.2026 16:35я публикую эту статью в надежде, что вы поможете подсветить все возможные косяки
<перед этим>
я планирую внедрить UCF в свой формат бинаризации произвольных данных VaryPack, который используется в моей децентрализованной базе реального времени Giper Baza, у которой есть все задатки стать основой Web4
Вам уже подсвечивался самый главный косяк, который называется Трагедия общин. Из-за этого косяка ваш Web4 является сказочной страной феечек, а без Web4 у вас не получится всё остальное.

nin-jin Автор
05.01.2026 16:35А весь Open Source спонсирует ЦРУ, да.

Flammmable
05.01.2026 16:35Если завтра бюджет Canonical сократится в 2 раза, жёсткий диск на вашей Ubuntu не уменьшится пропорционально.
Если послезавтра Canonical сообщит, что для покрытия бюджетной дыры ей надо ввести рекламу, на вашей установочной флешке всё ещё останется дистрибутив без рекламы.
А если вы честно спроецируете данные гипотетические события на ваши мечтания, то поймёте их принципиальное отличие от OpenSource.

shasoftZ
05.01.2026 16:35Насколько я понимаю основные плюсы по сравнению с utf-8 это
1. Более компактное представление
2. Скорость кодирования/декодирования
При используя архиватор получим ещё более компактное представление. А декодирование там будет точно также шустро работать. Да и кодирование будет не сильно тормозным.
Т.е. "плюсы" именно такой кодировки выглядят сомнительно
nin-jin Автор
05.01.2026 16:35Неужели такая простая мысль, что любой дополнительный пре/пост-процессинг не может быть бесплатным, слишком сложна для современного поколения разработчиков?

Flammmable
05.01.2026 16:35Неужели такая простая мысль, что любой дополнительный пре/пост-процессинг не может быть бесплатным, слишком сложна для современного поколения разработчиков?
Странновато это слышать от человека, мечтающего о бесплатных серверных мощностях :)))))

nin-jin Автор
05.01.2026 16:35Про возможность безопасно грохать базу на проде я даже не рассказываю, а то ещё помрёте от кринжа.

shasoftZ
05.01.2026 16:35Так вы то предлагаете делать этот пре/пост-процессинг ВСЕГДА. Т.е. выполнять всегда не бесплатную операцию.
Я же говорю о том, что если всегда такая операция нужна, то имеет смысл использовать что-то боле специализированное для упаковки/распаковки. А если не всегда нужна, то нет смысла выполнять трансформацию.
nin-jin Автор
05.01.2026 16:35Я не предлагал никаких операций в дополнение к utf8 кодированию. Я предложил одно кодирование заменить на другое сопоставимой сложности, но при этом большей эффективности.

shasoftZ
05.01.2026 16:35В том то и дело что вы хотите одно кодирование заменить на другое кодирование. При этом есть варианты более эффективные чем ваш. О чем вам и написали указав на тот же zip
Т.е. как идея, ваш вариант хороший. Но на практике нет никаких предпосылок для него.

Cfyz
05.01.2026 16:35Так ваш вариант кодирования по сути требует безальтернативного перекодирования в более удобное представление и обратно для использования внутри приложения, иначе все манипуляции со строками становятся алгоритмически сложнее. Тогда как UTF-8 в большинстве случаев можно использовать as is во всем приложении от диска и сети до преобразования и вывода.
Именно UCF означает постоянный пре/пост-процессинг на границе компонент.

nin-jin Автор
05.01.2026 16:35Как есть utf8 тоже алгоритмически не так уж просто использовать. Родная кодировка Windows, MacOS, Java, JS - UTF-16.

Cfyz
05.01.2026 16:35Любую UTF строку элементарно алгоритмически использовать, там отличие только в размере элемента массива.
Чего в мире больше, UTF-8 или UTF-16, вопрос дискуссионный, но скорее академический.
Суть конечно в том, что UTF возможно придется конвертировать. UCF совершенно точно обязательно надо конвертировать, причем скорее всего в тот же самый UTF.

eandr_67
05.01.2026 16:35Слишком хрупко: повреждение кода переключения алфавита ломает не единственный символ, как в UTF-8, а весь блок символов до следующего кода переключения алфавита.
Значения типа char и array of char. Да, для пользователя JavaScript или Python проблема может быть неочевидна, т.к. в этих языках есть только тип string. Но в компилируемых языках программирования есть не только строки, но и отдельные символы, и массивы символов, не тождественные строкам. И для них ваши оценки экономии объёма не имеют смысла, т.к. каждый символ, включая ASCII, придётся кодировать минимум 2 значениями (код алфавита и код самого символа в алфавите), что может привести не к сокращению, а к раздуванию объёма данных.
Операции со строками - от сравнения до регулярных выражений. Во многих из них придётся вводить дополнительные накладные расходы. Даже в банальной конкатенации строк придётся либо вводить дополнительные проверки для корректной вставки кодов переключения алфавитов на границах склеиваемых строк, либо смириться с забиванием строк заведомо лишними кодами переключения алфавита, съедающими экономию места и замедляющими сравнение строк. Вы оценивали только кодирование/декодирование, но никак не оценивали усложнение работы с содержимым строк при использовании вашей кодировкой.
Бессмысленность экономии на спичках. Экономия на символах имела смысл во времена PDP-11 c 56 Kb RAM, но при современных объёмах оперативной и внешней памяти - зачем??? Остаётся только передача по сети. Но на малых объёмах данных такая экономия не даст заметного выигрыша (объём служебной информации передаваемого по сети пакета данных никак не уменьшается). А при больших объёмах стандартизированные много лет назад механизмы сжатия трафика (встроенные и в серверы, и в браузеры, и в библиотеки, используемые в языках программирования; и нет - это не zip, так что претензии к скорости работы не принимаются) обеспечат несравнимо лучшее сжатие текстов, чем ваша кодировка.
P.S. Если же вы собираетесь использовать свою кодировку только для чтения/записи данных, а внутри кода использовать другую кодировку, то это тем более лишено смысла, т.к. вы лишь раздуваете объём используемой кодом оперативной памяти.

nin-jin Автор
05.01.2026 16:35В современных реалиях данные передаются в структурированном виде. Так что повреждение одного байта - это уже не "ой, ну пользователь сам поправит если надо", а "данные не могут быть прочитаны". Даже если это, казалось бы, текстовый JSON.
Хз о чём речь. Внутреннее представление в программе может быть любое. И любая кодировка потребует конвертации во внутреннее представление и обратно. В некоторых случаях, типа Go или Rust, внутреннее представление в UTF8, тогда чтение строки в той же кодировке позволяет ограничиться лишь валидацией. Но в общем случае всё не так радужно. В JS, как видите, приходится перегонять в UCS-2 и обратно даже UTF8.
Проверка там не сложная. Достаточно хранить вместе со строкой её последний режим.
От того, что сжатие куда-то там встроено, оно не становится ни невесомым, ни мгновенным. Сам я наблюдал, например, утечки памяти в вебсокетах при включении сжатия. После шифрования сжатие бесполезно. И до шифрования в случае маленьких строк тоже. Магическое мышление в духе "компрессор как-нибудь сам разберётся" тут не работает.

ss-pol
05.01.2026 16:35Я на 4 отвечу. Я уже написал здесь, но мысль важна, я её повторю.
Основной недостаток юникода, на мой взгляд, не в избыточности, а в том что он не предоставляет информацию о языке. То есть кириллическая строка, например, может быть русской, болгарской, украинской. Латинская - английской, немецкой, итальянской и т.п.
Вот это является основным недостатком юникода. Так что новый юникод, с информацией о языке нужен! Можно, конечно, теоретически, продублировать латинский алфавит для итальянского, немецкого, французского и т.п. В принципе юникод позволяет расширение. Но это, на мой взгляд, будет слишком расточительно. Поэтому идея хранить какую-то дополнительную информацию о строке в самой строке, в принципе верна и перспективна.

czz
05.01.2026 16:35Но у юникода нет такой задачи, и не очень понятно, почему она должна быть. В своем же ПО вы всегда можете иметь структуру данных, где у вас есть и строка, и любые метаданные.

ss-pol
05.01.2026 16:35Язык это же не отделимое свойство, которое можно применить к тексту, типа шрифта, цвета или отступов, это неотъемлемое и неотделимое свойство любого текста, слова. Каждый текст написан на каком-то языке. Почему и зачем это должно храниться где-то отдельно? По-моему очень странная идея.

czz
05.01.2026 16:35Строка символов — это более низкий уровень абстракции, чем текст. Текст может быть репрезентирован в виде строки символов, но строка символов не обязательно представляет собой текст, например, это может быть произвольный набор букв или ASCII art. У текста же есть язык, грамматика, смысл, авторские права и еще множество вещей, которые относятся к тексту, но не относятся к произвольной строке символов.

ss-pol
05.01.2026 16:35Текст может быть репрезентирован в виде строки символов, но строка символов не обязательно представляет собой текст, например, это может быть произвольный набор букв или ASCII art.
Произвольный набор букв (имелось в виду случайный набор?) и ASCII art не требуют языка, здесь я согласен. Но нам ничего не мешает приписать им и какой-то произвольный язык...
> У текста же есть язык, грамматика, смысл, авторские права и еще множество вещей, которые относятся к тексту, но не относятся к произвольной строке символов.
Язык вполне относится. Если мы используем строку для хранения SHA256 в BASE64, то нет, но это уже скорее набор байт, а не текст. Но любая строка текста написана на каком-то языке.
czz
05.01.2026 16:35Но нам ничего не мешает приписать им и какой-то произвольный язык...
А потом, внезапно, две строки с одинаковым текстом у вас оказываются не равны.
Вы обошли ключевое понятие — уровни абстракции.
Самый низкий: массив байтов. Он может обозначать символы, может бинарные данные. На этом уровне намеренно не задается семантика хранимых значений.
Более высокий: набор символов. Один и тот же символ ("ъ") может использоваться в разных языках, может вне языка, может хоть в роли части орнамента. На этом уровне намеренно не затрагиваются такие понятия как слово, текст, язык. Unicode задает только набор символов.
Еще более высокий — состоящий из символов текст, по отношению к нему уже можно применить понятия язык и слово.
Из того, что unicode является только набором символов, и намеренно создан, чтобы работать именно на этом уровне, не затрагивая другие, следует то, что он не определяет и не должен определять, как интерпретировать эти символы в тексте.
Давайте представим, что у нас уровни 2 и 3 смешались.
Вот текст:
fn main() { println!("Привет!"); }На каком он языке? Может показаться, что на английском, но нет, в английском нет таких знаков препинания и слова fn.
Ок, припишем ему язык Rust, как есть. И вдруг возникает куча вопросов:
Слово "привет" — это еще Rust или уже русский язык? Или надо приписать ему два кода языка?
А это точно русский, может быть другой славянский язык?
А кавычки — это русский язык или Rust?
А как терминал должен работать при выводе текстов на разных языках?
А как в текстовом редакторе отметить, что это русский язык?
И как вообще программы должны отображать, на каком языке написан фрагмент текста, и зачем им нужно это делать?
А если человек в мессенджере ввел "Привет", и мы получили это в нашей программе через API, то это на каком языке? А если он в следующим сообщением в этом же мессенджере отправил "добры дзень", то это на каком?
Все эти вопросы — следствие того, что мы попытались применить параметры, свойственные тексту, к уровню символов, где они неприменимы, и где нам даже неоткуда значения этих параметров получить.

ss-pol
05.01.2026 16:35А потом, внезапно, две строки с одинаковым текстом у вас оказываются не равны.
Имеется в виду, две строки с одинаковым начертанием? В юникоде ровно точно такая же проблема присутствует (лат. С и кир. C). Я эту проблему не пытаюсь решить.
> 2. Более высокий: набор символов. Один и тот же символ ("ъ") может использоваться в разных языках, может вне языка, может хоть в роли части орнамента. На этом уровне намеренно не затрагиваются такие понятия как слово, текст, язык. Unicode задает только набор символов.
Я поддержал бы в принципе такую идею, если бы юникод решил такое воплотить и ограничился уровнем 2. Но к сожалению, создатели пошли по другому пути и взяли что-то среднее между уровнем 2 и уровнем 3. Если бы они ограничились бы уровнем 2, то у нас бы не было кириллической "С" и латинской "C".
А раз уж они начали отличать латинскую C и кириллическую, то что нам мешает отличать немецкую и французскую?
> Слово "привет" — это еще Rust или уже русский язык?
очевидно же русский
> А это точно русский, может быть другой славянский язык?
это решает автор текста
> А кавычки — это русский язык или Rust?
не важно, их можно включить куда угодно, либо вообще вынести отдельно, вопрос обсуждаемый и решаемый. Вынести отдельно наверное проще, либо, как вариант, расположить их на одинаковом месте во всех подкодировках. Это второстепенный вопрос.
> А как терминал должен работать при выводе текстов на разных языках?
Текстовый терминал, который работает только в текстовом режиме? Как и сейчас. Ну, если у него есть соответствующий шрифт, то отображать текст, если нет - то нет, а что ещё он может делать?
> А как в текстовом редакторе отметить, что это русский язык?
Ну это вообще можно определить автоматически, при выборе раскладки клавиатуры, но если есть необходимость поменять язык, то можно предусмотреть и такую функцию, более того, в либреофисе уже есть такая функция - выделяешь текст и задаёшь язык. В чём проблема-то? По умолчанию язык берётся из настройки клавиатурного ввода.
> А если человек в мессенджере ввел "Привет", и мы получили это в нашей программе через API, то это на каком языке? А если он в следующим сообщением в этом же мессенджере отправил "добры дзень", то это на каком?
В чём проблема, я не понял. Мы через API получили строку, в которой задан язык, вот какой задан, такой и язык.
czz
05.01.2026 16:35Имеется в виду, две строки с одинаковым начертанием? В юникоде ровно точно такая же проблема присутствует (лат. С и кир. C). Я эту проблему не пытаюсь решить.
Символы — это не начертание. Один символ может иметь разные начертания, и наоборот, какие-то начертания разных символов могут быть похожи.
Так же, как не стоит смешивать символы и текст, также не стоит смешивать и символы с их начертанием.
Конкретно здесь имеются в виду строки с одними и теми же символами, например:
строка "hotel" с английским языком и слово "hotel" с французским языком,
некая строка с указанным языком и та же строка без указания языка.
А раз уж они начали отличать латинскую C и кириллическую, то что нам мешает отличать немецкую и французскую?
Не смешивайте символ и его визуальное представление — часть вопросов отпадет.
В чём проблема-то?
Один написал "привет" с русской раскладкой, другой с беларусской, третий вставил из веб-страницы — и у вас три одинаковых по символам строки, которые при сравнении дают false.
Например, для Rust нет раскладки клавиатуры. То есть, вы неявно добавили к нашему вопросу еще и некое соответствие между языком и раскладкой клавиатуры, которое, вообще говоря, не один-к-одному, и не всегда имеется.

nin-jin Автор
05.01.2026 16:35Я бы очень не хотел, чтобы помимо латинской «с» и кирилитической, у нас были бы еще и французская, вьетнамская и суахили. Это же одна и та же буква по сути. Но вот тегов языка очень не хватает, да.

ss-pol
05.01.2026 16:35Я бы очень не хотел, чтобы помимо латинской «с» и кирилитической, у нас были бы еще и французская, вьетнамская и суахили.
Ну тогда надо убрать "латинскую" "c" и "кириллическую" "c" и оставить просто "c".
И да, возможность задать язык очень нужна.

tenzink
05.01.2026 16:35Мне кажется, что не получится ввести рабочее определение текста языка. На каком языке написаны тексты:
Программа на python с комментариями на русском
А научпоп, где наряду с русским текстом используются греческие буквы и символы шахматных фигур
К какому языку отнесена запятая между \alpha x, ы?

ss-pol
05.01.2026 16:35Программа на python с комментариями на русском
python это подмножество английского, не уверен что ему нужная своя подкодировка, можно обойтись и английской.
Очевидно же, что файл может содержать текст на разных языках, в частности на русском и английском. Можно хоть каждый символ делать на своём языке. В принципе в любом месте может понадобиться переключить язык.
> А научпоп, где наряду с русским текстом используются греческие буквы и символы шахматных фигур
Ну так греческие буквы или слова будут вставками греческого, а символы шахматных фигур - вставками "шахматного". Для каких-то математических символов тоже понадобится своя подкодировка математического языка. В сущности, разница с юникодом лишь в способе кодирования. Моя идея - увязать этот способ и с языком заодно.
Моя идея с языками не относится непосредственно к способу кодирования. На самом деле, можно и сам юникод расширить французским, немецким, итальянским алфавитом, он это позволяет. Просто вместо латинской С и кириллической С будет ещё французская С, немецкая С и т.п. Но это довольно расточительно, так как различных языков более 7 тысяч (а есть ещё спец. языки), а задать режим кодировки один раз в начале строки не так расточительно, на мой взгляд.
> К какому языку отнесена запятая между \alpha x, ы?
Со знаками препинания (и пробельными символами) можно поступить по-разному. Либо вынести их в отдельную группу, либо как-то иначе их сделать одинаковыми (например равными по порядковому номеру) во всех языках. Тут не уверен как лучше. Если выносить в отдельную группу, то знаки препинания будут занимать 4+ байт. В принципе терпимо, так как они редко встречаются.

kuza2000
05.01.2026 16:35Да, для пользователя JavaScript или Python проблема может быть неочевидна, т.к. в этих языках есть только тип string
Ну не правда, в питоне есть bytes. Встроенный тип, уже много лет. Наверное, с момента распространения юникода. На строки похож, но внутри - байты. Очень полезная иногда вещь.

fenrir1121
05.01.2026 16:35На строки похож, но внутри - байты.
Настолько похож, что в python2 он назывался string :)

kuza2000
05.01.2026 16:35Ну, это было в старые добрые времена, когда ещё не было всяких енитих ваших юникодов))

shai_hulud
05.01.2026 16:35Не вижу как можно перекодировку с этого в UTF-16 и UTF-8 векторизовать. Без векторизации все эти ужимки и приседания будут медленее текущих решений по перекодированию.

nin-jin Автор
05.01.2026 16:35А текущие решения по перекодированию кодировок переменного размера каким таким волшебным образом векторизуются?

shai_hulud
05.01.2026 16:35Давно уже в стандартных библиотеках языков. Статьи про ускорение пишутся уже не первое десятилетие. https://woboq.com/blog/utf-8-processing-using-simd.html на первой странице Гугла.

black_warlock_iv
05.01.2026 16:35Четырёх байтовые: UCS-4 фиксированной ширины и UTF-32 — переменной
Это одно и то же.
UTF-8 довольно простой, если не считать приколов с суррогатными парами
В UTF-8 нет ниаких "приколов" с суррогатными парами, суррогатные пары -- исключительная вотчина UTF-16
Но большая часть из них до сих пор не используется
Сегодня не используется, а завтра используется.
решать вопрос битых данных надо не на уровне кодирования текста, а на транспортном уровне
Вот есть у вас бинарный файл неизвестного формата, требуется найти в нём текстовые куски, как вы решите тут "вопрос битых данных"? Или есть битый диск со слетевшей файловой системой, как вытащить с него все возможные текстовые данные?
проблема компактного представления остаётся
Нет такой проблемы, вы её выдумали только ради того чтобы герически решить.

nin-jin Автор
05.01.2026 16:35Это одно и то же.
https://www.ibm.com/docs/en/i/7.6.0?topic=unicode-ucs-2-its-relationship-utf-16
В UTF-8 нет ниаких "приколов" с суррогатными парами, суррогатные пары -- исключительная вотчина UTF-16
https://en.wikipedia.org/wiki/UTF-8#Surrogates
Вот есть у вас бинарный файл неизвестного формата, требуется найти в нём текстовые куски,... Или есть битый диск со слетевшей файловой системой, как вытащить с него все возможные текстовые данные?
Нет такой проблемы, вы её выдумали.

black_warlock_iv
05.01.2026 16:35Сслыка про UCS-2 и UTF-16. Я говорил про UCS-4 и UTF-32.
То, что нет кодепойнтов от U+D800 до U+DFFF -- это не "приколы с суррогатными парами", это просто факт, что таких кодепойнтов нет. Впрочем, по крайней мере понятно, о чём, возможно, вы хотели сказать.
Нет такой проблемы, вы её выдумали.
Есть. Как и ещё миллион разных ситуаций, где текст обрубается в произвольном месте между байтами. Даже банально из-за программных ошибок когда неверно индекс подсчитан -- я сам такие делал и хорошо, что Rust проверяет такие вещи и проверяет именно с помощью свойств UTF-8.
Подумайте также вот над чем. 1. UTF-8 придумал Кен Томпсон, при этом Кен Томпсон понимал что делает и зачем. 2. Кен Томпсон сделал код самосинхронизирующимся. 3. Из 1 следует: если бы это не было необходимо, Кен Томпсон не стал бы делать код самосинхронизирующимся. 4. Из 3 и 2 следует: самосинхронизация необходима. Таким образом, строго логически можно доказать, что самосинхронизация необходима.

MountainGoat
05.01.2026 16:35Ваше доказательство требует, чтобы Кен Томпсон был безошибочен сейчас и в будущем. Это неплохо бы доказать.

nin-jin Автор
05.01.2026 16:35А, ну да, UCS-4 в какой-то момент "переопределили". Славно, что мы выяснили этот очень важный вопрос.
Да-да, я не понимаю, это другое.

VMarkelov
05.01.2026 16:35Читаю и не понимаю, как в итоге это всё должно работать. Вот две цитаты из текста:
Одним байтом переключились на нужную страницу и далее в рамках этой страницы каждый байт со значением до 128 — один символ
Кстати, да, французам с диактрикой и украинцам с их
Ґмы помочь не сможем — придётся им переключаться между страницами, что в худшем случае выливается в 3 байта на одиноко стоящий такой символ вместо 2 у UTF-8Вопрос 1: Почему, например, тот же
Ґнельзя добавить в блок "украинский" (да и во французском не так много диакритики)? 128 символов для алфавита выглядит вполне достаточно, чтобы нужные символы впихнуть. Или принципиальная позиция: что сейчас с диакритикой, то тут будет кодироваться 3 байтами? Так для украинского эта буква цельная. Иначе мы можем договориться, что в русском блоке не будет "ё" и "й", потому что это на самом деле "е" и "и" с диакритикой. Как вообще определяется что идёт в основной блок, а что в расширенный?Вопрос 2: мне так кажется, что в большинстве языков с латиницей диакритика есть, в некоторых её даже очень много. Значит, для этих языков размер итогового "текста" вырастет по сравнению с utf8? Например финский или шведский с их ö/ä и ø.

VMarkelov
05.01.2026 16:35Читаю и не понимаю, как в итоге это всё должно работать
Если точнее, то я не понимаю, как всё будет биться на блоки.

nin-jin Автор
05.01.2026 16:35Проблема в том, что в Юникоде символы таких языков, как французский и украинский, находятся в нескольких разных блоках, от чего приходится тратить байты на переключение между ними.
Да, но не сильно: +1 байт за каждую одинокую диактрику.
Блок в данном случае - это просто 128 последовательных пода и всё.

debagger
05.01.2026 16:35Ну чтош, осталось дело за малым, пропихнуть этот формат в качестве стандарта и убедить микрософт, гугл, мозиллу и эпл внедрить его в браузеры и ОС.

Siemargl
05.01.2026 16:35Хоть кто-то мыслит нестандартно.
Может конечно и часть идей ТС откинется как нежизнеспособная.
Но массовке не оценить =)
Особенно, если её поддразнивать, так и будут минуса.

Snoubort
05.01.2026 16:35Автор просто выдумывает велосипед без внятных причин это делать. По этому ему справедливо и выдают минусов.
Я уж не говорю про сразу ряд неочевидных проблем, которые описали люди в комментариях.

vybo
05.01.2026 16:35По идее раз 23 "быстрых" символа взяты из ASCII, то для ASCII-блока не лишним был бы свой отдельный набор быстрых символов, а то он самым слабым выходит

nin-jin Автор
05.01.2026 16:35Логично, а какие символы были бы наиболее полезны в дополнении к латинице?

vybo
05.01.2026 16:35Думаю, что тут всего вернее пробежаться по разным однобайтовым кодировкам и кастомным клавиатурам, что чаще встречается — то и востребованнее. Неразрывный пробел, евро, градус, параграф, несколько видов копирайта и тому подобное

nin-jin Автор
05.01.2026 16:35Как минимум туда стоит поместить распространенную диакритику, что позволит записывать европейские языки в столько же байт что и utf8. Прада это потребует соотвествующей нормализации.

vybo
05.01.2026 16:35Если речь про цельные символы вроде Ä, то сколько-либо адекватный их набор туда вряд ли влезет (в сообщении выше я еще забыл написать очевидное про тире и кавычки разных видов, одни они уже наверняка отожрут треть или четверть места), а вот комбинируемая диакритика может и была бы неплоха для новых текстов, но думаю, что цельные знаки в существующих текстах и клавиатурах (да и в софте, телеграм вон комбинируемую по сей день не тянет) сильно популярнее сборок, так что при взаимно однозначной конвертации экономия выйдет спорная. По уму еще можно на большом массиве латинописьменных текстов пройтись бы простейшим скриптом на статистику по символам ну или положиться на ответы ллмок, раз уж предсказание символов по огромной выборке как раз лежит в основе их действия

apevzner
05.01.2026 16:35Кодировка UTF-8 обладает одним важным достоинством: алгоритм парсинга имени файла (полного, с путём) в ней ничем не отличается от ASCII. Т.е., алгоритм для ASCII будет работать и с файловыми путями в UTF-8, не замечая разницы.
Я ведь правильно понимаю, что UCF этим свойством не обладает?

nin-jin Автор
05.01.2026 16:35Сомнительное свойство, конечно, но обладает. А вот utf16 - нет, и никто не страдает без него.

Cfyz
05.01.2026 16:35Сомнительное?
Это одна из основных причин, почему UTF-8 относительно шустро стал стандартом де-факто. В большом количестве случаев (большинстве, кроме непосредственно вывода) алгоритму наплевать на конкретные языки и вся обработка сводится к манипуляции обезличенными наборами байт (слов, двойных слов).
UTF позволяет использовать одно и то же представление для хранения на диске и в памяти, для передачи по сети и между компонентами. Это очень удобно.

nin-jin Автор
05.01.2026 16:35Сомнительное, ибо такие хаки приводят к уязвимостям.

Cfyz
05.01.2026 16:35Никакой это не хак, вот вообще. Вы либо меня не поняли, либо сознательно передергиваете.
В качестве элементарного иллюстративного примера можно привести разбор JSON с его произвольным UTF-8 в строках. Парсеру не надо вообще ничего знать про кодировки, ему что ASCII, что UTF-8, все едино -- достаточно искать разные скобки и кавычки.
То есть строку в UTF-8 можно прочитать из файла или принять из сети и без преобразования распарсить и передать фрагменты дальше.
Вы в UCF упомянули небольшой набор "базовой ASCII пунктуации", но разница тут фундаментальная. Потому что дело не только в конкретном парсинге от скобки до скобки.
Над UTF строкой можно выполнять различные операции с привычной алгоритмической сложностью. В случае UCF это невозможно и надо сначала преобразовать строку к какому-нибудь вменяемому виду -- например UTF или UCS.

Goron_Dekar
05.01.2026 16:35Вы же, надеюсь, помните, что в строковых массивах не должно быть нулевых байтов? API ядра всё ещё сишное...

nin-jin Автор
05.01.2026 16:35Сишные псевдостроки, очевидно, не подходят для хранения UCF как и любых кодировок с режимами. А апи ядра нужно скармливать строки в его кодировке, которая у разных ядер разная.

Goron_Dekar
05.01.2026 16:35Апи ядра надо скармливать строки в той кодировке, в которой вы хотите видеть логи и названия файлов.

pvvv
05.01.2026 16:35leb128

nin-jin Автор
05.01.2026 16:35Каждый пробел в русском тексте будет кушать 3 байта.

pvvv
05.01.2026 16:35А в UTF8 как? Там два байта для кодирования всего 2048 (-128) символов, вместо 16384 у leb128.
Кодировки с переменной длиной - дичь, сколько там всего долей процента текстовой информации вообще по сравнению с каким-нибудь видео, чтобы не сношать уже мозг и какой-нибудь фиксированный utf32 использовать. А лишние нулевые байты любая примитивная компрессия поверх и так уберёт.

ss-pol
05.01.2026 16:35Четырёх байтовые: UCS-4 фиксированной ширины
Эта "фиксированная ширина" тоже достаточно условна и работает пока мы не используем диакритику.

pvvv
05.01.2026 16:35там место под коды в уникоде закончилось что ли, чтобы все эти точечки, кружочки, чёрточки, домики и всевозможные их комбинации вместе с буковками закодировать отдельно? не настолько же их много.

subzey
05.01.2026 16:35Кажется, вы изобрели японскую ISO-2022-JP, со всеми её минусами. Из-за переключения режима кодирования эта кодировка сложна при обработке строк и создаёт риски XSS, настолько, что современные браузеры её или не автодетектят или вообще не поддерживают.
Её «младшая сестра» Shift-JIS проще, но даже её уже почти полностью вытеснила UTF-8.

cpud47
05.01.2026 16:35Такая кодировка не позволяет делать zerocopy парсинг. Плюс, она не позволяет брать подстроки (что часто используется в дедупликации).
Вообще кодировка скорее похожа на доменноспецифичный алгоритм сжатия, чем на собственно кодировку. Но в таком случае, кажется, можно сделать сильно эффективнее(быстрее, компактнее), если подходить к этому именно как к сжатия (и можно жать не байты, а напрямую кодпоинты).
P.S. кажется Вы это подразумевали, но было бы хорошо добавить в статью чёткое указание, что это кодировка для передачи, а не для использования в оперативной памяти.

xenon
05.01.2026 16:35Мне кажется, проблема компактности текста мало где актуальна. Тексты в целом весят мало. С юникодом дофига других проблем (начиная с того, что есть много юникодов). Есть даже уязвимости, когда по разным collation можно взламывать сайты. Что-то вроде регистрации юзера ádmin (первый символ - не обычныая "a"), но иногда при логине или восстановлении пароля эта запись может находиться и обрабатываться первой.
Я бы был очень рад если бы появилось решение этой проблемы, и у нас была бы единая простая кодировка (пофиг, пусть объемная) с которой было бы просто и понятно работать, почти как с ASCII.

alliumnsk
05.01.2026 16:35Забавно, если скопировать URL из браузера в буфер обмена, получаем %D0%90%D0%90, как будто живы еще системы не работающие свыше 7 бит, а другие вещи мы депрекатим.

yrub
05.01.2026 16:35ВЕРДИКТ:
Статья — отличный пример инженерного онанизма.
Технически — он решил задачу "как упаковать плотнее".
Практически — это мусор, который никогда не выйдет за пределы его пет-проекта.UTF-8 победил не потому, что он самый компактный.
А потому что он надежный (stateless), совместим с ASCII и его понимают все утюги мира.
Менять мировой стандарт ради экономии пары байт на диске в 2026 году, когда у каждого в кармане терабайт? Ну удачи, Дон Кихот.
Главная проблема: СОСТОЯНИЕ (Statefulness)
В этой кодировке невозможен Random Access (произвольный доступ), невозможен seek, невозможно восстановление после битого пакета (потерял один байт переключения — весь остальной текст превратился в мусор).
2. Сжатие vs GZIP
алгоритмы работают на уровне энтропии.
4. Безопасность (Security Nightmare)
Stateful-кодировки — это рай для хакеров.
Как фильтровать XSS (вредоносный скрипт)?
В UTF-8 ты ищешь байты <script>. Они всегда одни и те же.
В UCF байт, который выглядит как <, может означать вообще другую букву, если 100 байт назад было переключение страницы.
WAF (Web Application Firewall) и базы данных охереют это проверять. Это дыра в безопасности размером с тоннель.
PS: самому было лень все это писать, автор займись чем-нибудь полезным, а это полный кринж

nin-jin Автор
05.01.2026 16:35У меня тоже для вас диагноз есть: https://page.hyoo.ru/#!=or9bsp_dv53a1

QuarkFusion
05.01.2026 16:35В UCF байт, который выглядит как <, может означать вообще другую букву, если 100 байт назад было переключение страницы.
это stateful кодировка, при чтении строки нужно помнить страницу и проблем нет, аналогично в UTF-8 при чтении с середины буквы
сразу напишу тут про вставку и подстроки: для подстрок либо откат назад для выяснения страницы, либо извлечение страницы из контекста; для вставки — просто дублирование страницы; для сравнения — нужна нормализация, но она и в юникоде нужна, при этом нормализация для страниц элементарна и сравнивать можно по хэшу (вероятностное сравнение, в реальности использовать солёные хэши), либо принять, что строки со вставками и без — разные

yurixi
05.01.2026 16:35В UTF-8 можно тыкнуть в середину текста, смещаясь и проверяя код найти начальный байт и получить символ. У вас символ в середине будет зависеть от страницы, которая задана неизвестно где.
Это значит вам дадут фрагмент с килобайт посреди мегабайтного текста, а он из однобайтных символов, но неизвестно какой страницы.
Так что очень сомнительно. Разве что, повторять код страницы каждые n байт. Но это уже кривовато выглядит. А если на кириллические буквы вместе с постоянным указанием страницы так и будет уходить два байта то вообще нет улучшения.
То что пробел между словами уже не 0x20 это, конечно, отдельный прикол.

Astroscope
05.01.2026 16:35Сначала был 7-битный ASCII и все телетайпы понимали друг друга. И было это хорошо.
Подождите, сначала были 5-битные телетайпы, гуглите Baudot/ITA-2. Пять бит - это 32 индивидуальных значения, более чем достаточно для 26 букв, 10 цифр, и набора знаков препинания вместе со служебными символами вроде перевода строки. Ну, как достаточно - два из служебных символов только то и делали, что переключали регистр с условно букв на условно цифры плюс знаки препинания, ну и обратно, так что при помощи нехитрого хака из пяти бит получалось 64 значения.

alabamaa
05.01.2026 16:35А где живет официальная спецификация данного изобретения, если она существует вообще? Или эта статья и есть спецификация? Чтобы уже начать с ней работать с полным пониманием сабжа. На вашем сайте тот же объем информации, что и в статье.

michael_v89
05.01.2026 16:35Сильно усложнится поиск и редактирование строк. Допустим мы ищем в тексте строку с русскими и латинскими символами. Она начинается с байта переключения на страницу русских символов. А в тексте такой последовательности байтов нет, он в основном на русском, и код переключения на страницу русских символов находится в самом начале. Поэтому стандартные механизмы поиска не будут работать. Тут вообще не очень понятно, как сделать поиск.
Регулярные выражения тоже работать не будут. Я не уверен, что в таком подходе они вообще возможны, в любом месте текста может встретиться код переключения страницы, который не соответствует паттерну. В крайнем случае надо будет переписать все движки регулярных выражений.
В текстовом редакторе при изменении позиции курсора надо будет каждый раз проверять каждый байт текста от позиции курсора в обратном порядке и проверять где там предыдущий код переключения страницы, чтобы определить, добавлять его при вводе символа или нет. Аналогично со вставкой текста, потому что он начинается с кода переключения символа.
Вы сэкономили несколько байт на передаче текста один раз, которые на фоне размера картинок выглядят незначительно, зато увеличили время процессора для его обработки постоянно.

nin-jin Автор
05.01.2026 16:35Тут вообще не очень понятно, как сделать поиск.
Почитать спеку, там всё есть.
В крайнем случае надо будет переписать все движки регулярных выражений.
Их уже переписали на матчинг по кодовым точкам, а не байтам.
В текстовом редакторе
Никто не будет двигать мегабайты туда-сюда на каждое нажатие клавиши в начале файла. Они работают не так, как вы наивно полагаете.
Аналогично со вставкой текста
Аналогично читаем спеку.
передаче текста один раз, которые на фоне размера картинок выглядят незначительно
Текст и картинки имеют разную критичность. Стыдно этого не знать.

michael_v89
05.01.2026 16:35Почитать спеку, там всё есть.
"Спекой" вы называете вот это коротенькое описание?
Почитал, ответа на этот вопрос там нет. Есть одна строчка с фантазией на тему что можно попробовать. Которая не будет работать.text = 'Тут есть строка 1ab и AB@>:0 1ab' // UCF: // \xA4 " C B \x95 5 A B L \x95 A B @ > : 0 \x95 \x81 \x9C a b \x20 \xA4 8 \x95 \x9C A B @ > : 0 \x20 1 a b // Т у т _ е с т ь _ с т р о к а _ 1 a b _ и _ A B @ > : 0 _ 1 a b str = 'строка 1ab' // UCF: // \xA4 A B @ > : 0 \x95 \x81 \x9C a b // с т р о к а _ 1 a b str = 'строка' // UCF: // \xA4 A B @ > : 0 // с т р о к а str = '1ab' // UCF: // 1 a b // 1 a bЗанятно, что у вас пробелы и цифры кодируются по-разному в зависимости от предыдущего текста. Так становится еще более непонятно.
Ну давайте, почитайте вашу спеку и напишите тут код функции поиска, которая будет выдавать только позицию 9 для первого случая, только 9 для второго случая, и 16 и 29 для третьего. Раз вам все понятно, это вам не составит труда.
Никто не будет двигать мегабайты туда-сюда
Они работают не так, как вы наивно полагаете.Я не говорил ни про какие движения мегабайтов туда-сюда. Читайте комментарий внимательно.
со вставкой текста
Аналогично читаем спеку.Там написано то же самое, что я написал в комментарии.
И нет, "её последний режим кодирования" не будет работать, потому что в текстовом редакторе можно делать вставку в середину строки. Дальше подумайте, что вы будете делать с исходной "ненаивной" строкой и как будете использовать позицию курсора.Их уже переписали на матчинг по кодовым точкам
И? От этого они магически будут не считать символами текста ваши переключатели страниц?
Текст и картинки имеют разную критичность. Стыдно этого не знать.
Стыдно подменять понятия. Критичность к разговору про размер данных не имеет никакого отношения. Вы заявили про компактность, но эффект в реальных приложениях незаметен. Не говоря уже о том, что обычный ZIP дает лучшую компактность.

nin-jin Автор
05.01.2026 16:35Согласен, на уровне байтов есть недетерминированность представления чисел и базовой пунктуации. Матчиться надо на следующем уровне абстракции - по кодовым точкам. На этом уровне нет ни недетерминированности, ни переключателей страниц. Поправил спеку, спасибо.
В идеале было бы всегда кодировать их одинаково, но тогда сломается совместимость с ASCII, что довольно неприятно. Хотя, есть одна идейка..

ruskrava
05.01.2026 16:35Кстати, да, французам с диактрикой и украинцам с их Ґ мы помочь не сможем — придётся им переключаться между страницами, что в худшем случае выливается в 3 байта на одиноко стоящий такой символ вместо 2 у UTF-8
Интересно почему так для украинского, ведь и у украинского и русского по 33 символа в афавите.

nin-jin Автор
05.01.2026 16:35Тут важно не количество, а диапазон кодов: https://ru.wikipedia.org/wiki/Кириллица_(блок_Юникода)#Компактная_таблица
whocoulditbe
Отбойники на дорогах довольно редко вступают в дело, но их почему-то всё ещё ставят вместо перекладывания всей ответственности на водителя.
nin-jin Автор