Комментарии 69
яЙНКЭЙН КЕР ОПНЬКН, Ю ЯОНП МХЙЮЙ МЕ ГЮЙНМВХРЯЪ
Да вроде никто и не спорит. Везде UTF-8 стандарт в интернете, предлагают просто расширить применение.
Почему-то вспомнилось "МЕЯ ВИДО?"
С принтером проще, он за драйвером спрятан.
Если честно, в Макоси с NSString тоже просто, там её внутреннее устройство наружу почти не торчит.
А что в BIOS? Я вообще не припомню в нём сколько-то значимых выходов за пределы ASCII, но я мог отстать от жизни.
(U)EFI весь разработан на стандартах Windows, включая формат файлов (адаптированный PE), и в кодировках текстовых строк используется UTF-16LE, включая имена разделов в GPT, внутренние строки самой EFI…
Что будет, если в С на котором пишут bios внезапно sizeof(char) станет UB, ведь символ в UTF8 не имеет задокументированного независящего от самого символа размера?
Да, использоваие stdint и прочих uint8_t немного спасёт (а в системном программировании я вообще ругаю людей, которые используют int), но, в любом случае, не все строковые литералы нуждаются в юникоде. Особенно в таком сыром, как utf-8.
ASCII – прост. Один символ – один байт, да ещё и старший бит не задействован.
Что касается сырости utf-8 – извините, ничего менее сырого нет. Ну кроме ASCII, но вам же мало будет?
А sizeof(char) не станет UB. Скорее вам запретят так просто разбирать строку на символы. В MacOS по сути давно спрятали это дело, чтобы узнать, как кодируется NSString – надо специально рыться в доках.
А sizeof(char) не станет UB.Какое вообще имеет отношение
sizeof(char)
ко всему этому?Скорее вам запретят так просто разбирать строку на символы.Не запретят. Строка в C/C++ вообще не имеет никакого отношения к работе с текстом. Она «заточена» под работу с байтами (да, вот так вот странно: тип
char
, в соотвествии со спецификацией, предназначен для работы с байтами, а вовсе не с символами… а тип std::string
, соответственно, с последовательностями байт… добро пожаловать в странный и причудливый мир C/C++).А для текста есть типы char8_t, char16_t, char32_t… ну и u8string, u16string, u32string… и «никто не уйдёт обиженным».
P.S. И нет — всё вышеописанное это не издевательство и не первоапрельская шутка, это то, что говорит стандарт. C++20 и следующий стандарт C (скорее всего C21). Стандарт ещё не принят, но N2231 в него уже согласились включить (это, собственно, почти единственное, по чему никаких разногласий не было).
Такой проблемы нет с UTF-16.
UTF-16 не панацея, в него тоже не все символы влазят. И будут у вас те же последовательности пар байт, только с заморочкой на big-endian/little-endian и свои особые "запрещённые" комбинации.
Там, где операции не зависят от кодировки (конечно же, с поправкой на общую корректность последоовательности), скорость будет примерно та же. Там, где нужно сравнивать-вырезать с учётом национальных алфавитов, суррогатных пар и др. дичи, UTF-16 сам по себе вам не поможет.
Там даже 4байт уже не хватает, чтобы все закодировать.
Единственное исключение для для документа на английском, где UTF-8 будет эквивалентен ASCII-8.
Но в принципе, согласен. Вкусовщина.
Это просто частный случай. Возьмите любой текст со смайликами, или на арабском, тамильском. И, внезапно, окажется, что уже не всё так просто.
В русском тексте используются не только буквы но и знаки. А они зачастую 8 бит в UTF-8.
«Я нашёл бо́льшую квартиру!»
«бо́льшую» — б — U+0431
о́ — U+043E U+0301
упс…
Вот одно все же есть у UTF8 неоспоримое преимущество. Он обратно совестим с latin1. Поэтому если софт сам не меняет строчки, а просто их передает, то он автоматически может быть переведен на юникод.
По этой причине в linux меньше проблем с кодировками чем в windows
Ровно те же проблемы, просто не так часто – поэтому про них периодически забывают и код ломается.
Вот как раз недавно чинил крэш из-за непарных суррогатов (приходили из браузера, не знаю уж, как юзеры умудрялись… JavaScript с этими строками нормально работал, а вот стандартная Маковская либа NSJSONSerialization падала).
Никакой способ кодирования не способен решить все проблемы работы с текстом.
Если бы думаете, что работа со строками — это работа с кодпоинтами, то вы ошибаетесь.
Например, в юникоде существуют комбинированные символы — и вам придётся с ними работать.
1. Этого лечения нет в любом UTF или UCS, потому что символ может занимать произвольное количество «кодовых пунктов» (UCP). Надо вам написать «бо́льшую», чтобы не путалось с «большу́ю» — пожалуйста: тут два символа по 2 UCP каждый, вторым идёт «COMBINING ACUTE ACCENT» (U+0301).
Так что сразу избавьтесь от этих иллюзий, что можно сделать какой-нибудь p++ и перейти гарантированно на следующий символ.
Более того, вы не можете сделать функцию вида step_left(wchar_t **pos), которая бы это отрабатывала надёжно во всех случаях, сдвигая pos — потому что на самом деле она должна быть step_left(wchar_t **pos, wchar_t *begin) — потому что может поступить на вход сломанный поток, в котором есть модификатор, но нет символа перед ним.
2. Даже если бы вы рассматривали кодовые пункты, а не символы — пункты с кодами U+10000 и более представляются «суррогатами» в виде пар UTF-16 кодов.
UTF-8 привлекает обратной совместимостью, это большой плюс.
Остальные виды хранения не дают того удобства, ради которого задумывался Unicode изначально, даже UTF-32.
Hello!Обе содержат по 6 символов (кодпоинтов, как хотите). Иии… что это нам даёт, собственно?
Hello!
Все алгоритмы работы с Юникодом, которые я видел, делились на два непересекающихся класса:
1. Делающих что-то полезное.
2. Индексирующих что-то «по номерам символов».
Всё что я видел, обычно сводилось к подходу «для русского и латинницы работает, а на остальное нам наплевать».
Но нельзя же с таким подходом выбирать кодировку для всех API и документов в операционке…
Особое удовольствие доставит замена в ненормализованной строке.
Строка для полноценной работы с ней нуждается в дополнительной индексации. И любые операции с ней будут опираться на эти индексы.
А посему, тип хранения уже становится не важен хоть UTF-8, -16 или -32, всё равно внутренне представление строки становится недоступным.
Я вот не могу представить себе ни одного мало-мальски осмысленного алгоритма, где бы это представление мне помогло… но почему за него бьются со страшной силой… зачем? почему?
Есть, пожалуй, одно место, где от этого может быть польза. Возьмите ту самую статью про и с краткой. Вот в этой самой букве «й» кратаку можно убрать бекспейсом…
Но вот ради этого, одного единственного, места в редакторе — всё с ног на голову переворачивать?
В основу документа легло предположение, что для хранения любого символа хватит 16 бит. Однако довольно быстро стало понятно, что этого недостаточно. Поэтому появились новые варианты кодировок — в том числе UTF-8 и UTF-16.
UTF-8 и UTF-16 не имеют отношения к тому, что «для хранения любого символа не хватает 16 бит».
UTF-8 лучше подходит для взаимодействия с системами, не ожидающими прихода многобайтных данных.
да, но…
Другие кодировки юникода содержат многочисленные нулевые байты. Утилиты могут посчитать их концом файла.
если утиль обрабатывает UTF-16 как UTF-8, то в большинстве случаев получится фигня даже без нулевых байтов.
самое забавное и интересное в статье — то, что мелкософт рекомендует использовать старые A-функции. я пропустил эту новость. эти функции считались пережитком прошлого, тяжелым наследием windows 95. и вот теперь это снова стильно, модно, молодежно. правда, как я понял, для всего этого великолепия нужен (относительно) свежий билд десятки.
Что-то сложно пока что представить сферу применения вот этого вот, кроме опенсорса, где можно любые правила диктовать.
https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/use-utf8-code-page
Недавно на Hacker News опубликовали манифест программистов из Тель-Авива.
А можно более точную ссылку чем «на Hacker News» указывать? если пользователь активно следит за HN — эта статья не особо полезна. Если не следит — то получается непонятно.
Python3:
>>> def йа_криведко():
... превед = True
Так что, похоже, вопрос нужно ставить так: а остались ли вообще ещё популярные языки, где это невозможно?
Так вроде уже добавили поддержку UTF-8.
Например, в UTF-16 символ A выглядит так: 00000000 01000001. В строке Си эта последовательность может быть обрезана. В случае с UTF-8 нулем является только NUL. В этой кодировке первая буква латинского алфавита представлена как 01000001 — здесь проблем с непредвиденным обрывом не возникает.
Читал я это, читал. И так, и эдак. Смотрел в источники по ссылкам. Но так и не понял, откуда берет своё начало утверждение и какую смысловую нагрузку оно несет: "В случае с UTF-8 нулем является только NUL
". Может кто-то пояснить?
NUL
». Хотя всё равно может быть чуть-чуть непонятно. Нужно понять какой именно NUL
имеется в виду. Речь идёт про вот этот вот NUL. А фраза означает следующее: из всех Unicode-символов (Code Point, если строго) в UTF-8 представлении нулевой байт содержится только в NUL
.Соответственно функции, которые считают этот самый
NUL
концом строки (это соглашение языка C) могут принять строку в UTF-8 представлении — и если им не нужно работать с символами (а на практике функций, которые просто передают строку откуда-то куда-то на порядок, а то и на два больше, чем всех остальных), то они продолжат прекрасно работать…Более того, масса других функций — тоже будут отлично работать. Например если у вас протокол использует служебные слова в US-ASCII (а таких тоже — больше, чем вы думаете), то всё тоже продолжит работать с UTF-8. Потому что US-ASCII в UTF-8 — имеет то же битовое представление… а символы вне US-ASCII — имеют в старшем разряде единичку в каждом байте (то есть никак не могут совпасть ни с одним US-ASCII символом).
«Лучше всего» в Эрланге сделано: строка — это односвязный список int32. Т.е. на каждый символ идет 8 байт: 4 на unicode-code-point (прямо в голом виде, никакая кодировка не нужна) и еще 4 на указатель на следующий символ-элемент списка. Расточительно, но никто не парится и все используют.
Группа разработчиков предлагает перейти на UTF-8