Pull to refresh

Comments 47

И вот именно поэтому для строки, с которой выполняются какие-либо операции помимо "получить от пользователя - сохранить - загрузить - вывести на экран" лучше задуматься об отказе от Юникода. Просто потому что иначе мы получаем одиноково выглядящие строки, которые кодируются по-разному, и одинаково кодирующиеся строки, которые выглядят по-разному, и нет этому конца...

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

Главная проблема: никто не хочет разбираться со стандартом и использовать подходящие инструменты пока хорошенько шишек не набьют. Отсюда и попытки работать со строками как с байтовыми последовательностями и пренебрежение локалями (после чего CP1251 при сохранении в ASCII может протерять половину) и лень проставлять, например, StringComparer для того же .NET/C#. И даты плывут точно так же у всех и регулярно

Интересно, а ни у кого не было идей сделать стандарт Unicode2, в котором все эти ошибки и странности были бы исправлены?

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

И вышло так, что USB передаёт как данные, так и просто много энергии (USB-PD). Скоро, наверное, воду научится передавать. И заранее не узнаешь, какая штука в цепочке "Источник - переходник - кабель - переходник - приёмник" будет точкой отказа. Удачи это дебажить как рядовому пользователю.

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

А где гарантии, что кабель стандарта USB-PD 2.0 будет работать как кабель для передачи данных по USB? А переходники? Источник? Приёмник, в конце концов. Мне нужны гарантии, желательно от дядюшки Сяо, у которого закупается вся дешёвая продукция по акции на 11.11.

Я к чему... Это очень муторно - контролировать всю цепочку передачи сигнала в экосистеме USB. По факту, там бардак похуже Unicode, кто во что горазд! В стране в 90-х не было такого броуновского движения, как сейчас в мировых (sic!) стандартах. Я с ДВФО, если что.

Если хочется, чтобы что-то работало на определённом стандарте - будьте добры, закупайтесь USB-тестером и вручную проверяйте всё - от разъёмов USB на передней панелт компьютера до картридера и повербанка. И в итоге получаются смартфоны с зарядкой 120W и позорным USB 2.0 для передачи данных. У меня сейчас на руках такой, без слёз не взглянешь, как будто с конченным инвалидом живёшь.

Стоп-стоп-стоп.
USB с PD и обязательной сертификацией — это Thunderbolt. И на 11.11 от дядюшки Сяо вы, АХУДИВИТЕЛЬНО, купите только паль.

Вручную проверять не нужно, достаточно просто помнить, что кроилово ведет к попадалову — проблемы покупателей пали остаются проблемами покупателей пали.

Остается иметь шнурки потоньше и подлинее, чтобы удоно таскать в кармане или рюкзаке, для устройств до 3.2, и потолще, для полноценных — причем вторым даже дом покидать не придется.

Скорее, скоро в розетку 220 будет включаться через usb-с

Чем больше разработчиков познакомится с этими ужасами Unicode, тем быстрее настанет момент, когда что-то лучше уж точно придумаем.
Я и до этой статьи читал, что внутри оно "не очень", а теперь точно уверен, что первый блин оказался комом. Ничего, зато ценный опыт.

Юникод это все еще лучше пачки кодировок.

и тут, я подозреваю, стоит сказать про номер версии.

Я начал изучать Go, сделал len() с этим эмодзи, получилось 13. Пока не вполне уверен, что я делаю, но вроде бы эта функция считает количество байтов.

В исходной статье был символ "🤦🏼‍♂️", а не "🤦‍♂️", поэтому такие различия.

Одна графема может состоять из нескольких кодовых точек

А есть ограничение на количество кодовых точек в одной графеме?

браузер отвис на 999999999, больше девяток дорисовывать я не стал...

Создатели Unicode считали, что 65 536 символов будет достаточно для всех человеческих языков.

Вот ещё в детстве меня это удивило — я знал что только китайских иероглифов где-то 60 тысяч, т.е. для остального места могло и не хватить 🤷 (а про всякие UTF-16 я узнал уже потом)

Китайские и японские иероглифы (по крайней мере большую их часть), по крайней мере в своременном начертании можно представить в виде комбинации радикалов, которых не так уж и много. Вот только Unicode не пошли по этому пути. Возможно чтобы не заморачиваться с исключениями возможно чтобы не заморачиваться с правилами группировки глифов. Однако среди CJK глифов есть и значащие иероглифы и радикалы, и комбинации нескольких радикалов.

Ну это я тоже заметил, хоть и очень далёк от всех этих CJK и пытаюсь вглубь даже не соваться. Сначала они добавляли всякие составные символы, хоть там диакритические знаки в два ряда могли идти (ṏ), но потом перестали. Видимо дошло, что так их можно хоть до бесконечности добавлять (мне символы с тремя рядами диакритических знаков в книгах попадались, и не раз). В общем, прекратили такие символы добавлять, но критерии добавления для меня не совсем ясны. А вот со всеми этими китайскими иероглифами всё обстоит иначе — их так и продолжают добавлять, хоть их и спокойно можно разбить на несколько знаков и даже в этом уникоде есть специальные значки для описания состава (⿲ и т.п.). Но их продолжают вставлять (хотя, повторяю, я от всего этого далёк). Ну и подозреваю, что с древнеегипетскими иероглифами, клинописными значками и проч. будут свои заморочки, например значки фестского диска помечены как Other Symbol 🙃

Стандарт юникода на мой взгляд слишком сложен, причем некоторые усложнения вроде ежегодного добавления эмодзи явно излишни. Впрочем и без эмодзи чудес хватает. Например на iOS 16 в некоторых локалях при неких мне неизвестных дополнительных условиях японские канзи начинали странно отображаться: некоторые радикалы в канзи менялись на другие. В iOS 17 наколько мне известно, это поправили.

Странно, что для четкого определения длины многоточечной графемы не ввели что-то типа спец символов (невидимых) для указания на начало графемы и ее длины. Наверняка там длина графем не больше 32х элементов, хватило бы 32 кодовых точек - маркеров графем.

Сначала мелкая придирка по тексту.

Область Unicode, выделенная под частное использование, содержит, в основном, шрифты, состоящие из значков.

Наверно, лучше сказать «покрывается шрифтами»? (Для понимания разницы читать про font fallback).

А по сути, автор раскрыл глаза людям, считающим, что UTF-8 — дерьмо, на страшную правду: это не UTF-8 — дерьмо, это Юникод — дерьмо. Надо же, какое невероятное удобство: теперь цвет лица в смайлике можно кодировать разными отдельными кодепоинтами, в то время как волшебная шляпа и плащ™ всегда кодируются одним и тем же! И вот РАДИ ЭТОГО у нас теперь нет возможности выделять память на стеке под строку заданного размера? РАДИ ЭТОГО создание шрифтов теперь больше напоминает разработку программы? РАДИ ЭТОГО мы потеряли O(1) в строковых алгоритмах? РАДИ ЭТОГО в процессе груповой работы (и, в частности, разработки) у нас периодически отлетает BOM? Остановите Землю, я схожу.

Вы только вдумайтесь. При использовании UTF-32 минимальное число байтов для хранения одного символа — четыре. Это четыре миллиарда значений. Этого МАЛО?! Туда влезут все живые и мёртвые языки, все смайлики из «Идиократии» на тыщу лет вперёд, и со всеми диакритическими вариациями. Но нет. Юникод просто автоматически означает UTF-8, так что, нечего удивляться, что он почти на 100% используется в веб-страницах. А как же ещё? Когда у нас имеется плавающее число кодепоинтов на один семантический символ, плавающее число байтов на один кодепоинт — это просто неизбежное зло. UTF-8 в Юникоде, это как формулировка в условиях тендера на госзакупках: «производитель компьютера любой, операционная система — macOS». Конечно, блин, можно извратиться, но это именно что извращения. Как и UTF-32.

Хорошим решением был бы стандарт, не основанный на кодепоинтах. Да, конечно, у такого подхода тоже есть минусы. Когда в будущем появятся люди с фиолетовым цветом лица, придётся их жутко дискриминировать, выдавая соответствующим смайликам значение на миллион-другой больше, чем большинствам. Или резервировать блоки для сохранения последовательной нумерации (что всегда дурно пахнет). Но лично я готов потерпеть.

Не понял претензий к UTF-8.

Некоторые из них перечислены в статье. (Подсказка: все пункты начинаются с «НЕ ПОЛУЧИТСЯ»).

Раньше у смайликов были прозрачные лица. Например, вот такие: : )

А я не понял претензий к UTF-32. Слишком много будет пустых старших байтов?

Насчёт неделимости графемных кластеров — не соглашусь. Решительно считаю возможность стирать диакритику у букв фичей, а не багом.

Вот сделали бы простую и удобную систему, как в телеграфе. 127-символьная (ну или 255-символьная) кодовая страница, и управляющие последовательности, эти страницы переключающие. И хоть древнеегипетские иероглифы пихай, хоть смайлики.

Ну и да -- диакритика хорошо бы была отдельной сущностью, как и буквы хангыли и других нелинейных систем письма.

Правда, появляется риск появления иНЖАЛИД дЕЖИЦЕ, если переключение где-нибудь потеряется, ну и тут можно что-нибудь предусмотреть.

А этого хватит для 60 тысяч китайских иероглифов?

Главное, что бы все программисты на PHP это знали.

Сейчас с популяризацией ChatGpt и других LLM, довольно интересна тема токенов, Уже сейчас на английском языке все популярные слова и графемы выделены в токены, думаю что если обучать генератор токенов на всех мировых языках в равной мере то должен получится UniToken в котором будут все используемые графемы и слова на всех языках.
Думаю что под капотом все еще будет UTF8 со всем наследием но можно будет выбирать уровень представления который удобен для нейронных сетей, людей и компьютеров: Токены слов -> Токены графем -> UTF8

В случае с PostgreSQL, varchar(255) - это тоже не количество графем, поэтому валидировать строку нужно по количеству юникод-точек, а не графем. А вот что выводить пользователю, вопрос.

ASCII: строка в 1024 символа потребует 1 кб памяти

UTF-16: строка в 1024 символа потребует 2 кб памяти

UTF-8 раньше: строка в 1024 символа потребует от 1 до 4 кб памяти

UTF-8 сейчас: строка в 1024 символа потребует... а фиг его знает, может и мегабайта не хватить!

Зато какое непаханое поле для стеганографии. Можно хоть аудио, хоть видео примешивать.

Сохранить криптотекст в метаданных дискографии любимой группы… в метаданных mkv… в потоке лирики и сабов…

После ASCII все сломалось )

Но это потому, что сломался сам ASCII

Автор недооценивает возможности современного Javascript:

function calcGraphemeCount(s, lang = 'en') {
	const segmenter = new Intl.Segmenter(lang, {granularity: 'grapheme'});
	return [...segmenter.segment(s)].length;
}

console.log(calcGraphemeCount('🤦‍♂️'));  //Выдаёт 1

Оптимизированная версия:

class MyString() {
	static segmenter_en_grapheme = new Intl.Segmenter('en', {granularity: 'grapheme'});
	
	static calcGraphemeCount(s) {
		let count = 0;
		
		for (const segment of MyString.segmenter_en_grapheme.segment(s))
			count++;
		
		return count;
	}
}

console.log(MyString.calcGraphemeCount('🤦‍♂️'));  //Выдаёт 1

Что здесь происходит:

  1. Создаём экземпляр класса Intl.Segmenter, который служит для разбиения текста на графемы, слова или предложения. В данном случае выбираем графемы.

  2. Применяем этот класс к строке, чтобы посчитать количество графем.

Если нужно, можно получить графему и её позицию по индексу в строке:

const segmenter_en_grapheme = new Intl.Segmenter('en', {granularity: 'grapheme'}),
      segmentObjs   = segmenter_en_grapheme.segment('abc🤦‍♂️def'),
      segmentObjAt5 = segmentObjs.containing(5);  //{segment: '🤦‍♂️', index: 3}

const grapheme    = segmentObjAt5.segment,                 //🤦‍♂️
      index_start = segmentObjAt5.index,                   //3
      index_end   = segmentObjAt5.index + grapheme.length; //8

Класс Intl.Segmenter можно использовать и для других целей, например, чтобы разбить японский или китайский текст, в котором нет пробелов, на слова. Правда сейчас пока в японском разбивает ну очень плохо, например, слово 間違う успешно считается за одно слово, но если поменять форму, например, на 間違えてる, то считается аж целых 5 слов (間+違+え+てる) вместо одного слова (間違えてる) или хотя бы двух слов (間違えて+る).

Впрочем, соглашусь, что, возможно, было бы интересно увидеть в JS свойство вида String.prototype.graphemeCount, чтобы можно было написать как-то так:

'🤦‍♂️'.graphemeCount;  //1

В исходной статье, кстати, был применён символ "🤦🏼‍♂️" (5 кодовых точек Unicode), а в переводе стал символ "🤦‍♂️" (4 кодовых точки Unicode). Из-за этого, если запустить примеры, то получится не тот результат, который написан в этих же примерах, т. к. в примерах указан символ 🤦‍♂️, а длина строки посчитана для символа из исходной статьи.

  • В тёмной теме Хабра часть картинок выглядит как "серое и чёрное на чёрном", ничего не разобрать

  • В главе "Я живу в US/UK. Надо ли мне вообще о таком задумываться?" потеряли выделение не-ASCII символов прямо в тексте главы, которое есть в оригинальной статье

  • Перевод низкокачественный, читается плохо

Лучше прочитать оригинал

Sign up to leave a comment.