Как стать автором
Обновить

Комментарии 58

йод - это три глифа или четыре? Что-то у вас проблема диакритики слегка упрощена. Плюс, вы не привели пример из корейского, где добавление символа к строке сокращает число видимых глифов.

В слове «йод» три графемы и три кодовые точки: U+0439, U+043E, U+0434. При этом возможна запись буквы «й» в виде пары буквы «и» и комбинируемого бреве U+0306. Эти примеры рассмотрены в статье.

Какие еще проблемы диактритики вы имеете в виду?

В конце статьи четко написано, что рассмотрены далеко не все примеры и особенности, потому что все их охватить в одном материале сложно.

Я неправильно прочитал. Вы очень вольно слова "длина" использовали, и я подумал, что на слово с диакритикой вы считаете длину 4.

Отличная статья! Я бы поставил плюс, да какие то школьники карму заминусовали)

Спасибо за оценку)

Давно здесь не было настолько интересных, полезных и при этом достаточно простых статей. Спасибо.

Спасибо! Очень приятно получить такой отзыв.

Спасибо большое за статью, все по полочкам.

В Firefox сейчас если в консоль прописать '깍'.length то возвращает 1, а не 3. Получается строка автоматически нормализуется или дело в другом?

Я по ошибке вставил в пример уже нормализованный глиф. Спасибо, что заметили. Уже исправил пример.

В Chrome вижу то же самое: '깍'.length возвращает 1, а не 3 (копипастил пример из текста статьи, сам не набирал)

А зачем эмодзи в объявлениях? Какой смысл в иконке фотоаппарата рядом со словом "фотоаппарат"?

Выделяет на фоне объявлений без картинки. Я вот даже в самых важных PR или сообщениях иногда эмоди ставлю.

‼️ Это делает надпись очень заметной ?

Как по мне, просто мусора в текст вкинули, тем и заметней.

Ну, а какая цель объявления?

А еще заметнее объявление делает хрень вроде такой:

?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?‍?

И всего 1 символ...

Выглядит как объявление о продаже рабов.

Эмодзи, как и wysiwyg редакторы, помогают продавцам лучше оформлять объявления и делать их более привлекательными для покупателей.


Пример с фотоаппаратом синтетический, чтобы показать особенности работы JS.

Отличная статья для понимания проблемы. А проблема подсчёта символов в юникоде очень сложная. Становится совсем грустно, когда твой сервис многоязычный. Эмодзи, диакритика, иероглифика, направление письма, плюс нехорошие ребята, которые обязательно попытаются использовать это, чтобы сломать систему.

Да, проблема правда очень сложная. Снимаю шляпу перед людьми, которые делали Intl.Segmenter и подобные вещи.

Если копнуть глубже, то ограничение по количеству символов скорее всего происходит от требования дизйнеров UI/UX, которое звучит примерно как "для читаемости и удобства объявление должно умещаться в поле такого-то размера".

Помещаем текст в блок заданного размера, проверяем сработал ли overflow, и всё, кодовые точки считать не нужно.

Правда есть недостаток при таком подходе - невозможно пользователю показать циферку с количеством символов. Зато есть и фича - никаких проблем с разной шириной символов (сейчас скорее всего максимальное количество символов занижено, чтобы "длинные" буквы не ломали вёрстку) .

Ваш метод подсчета абсолютно не жизнеспособен, к сожалению. Ограничивая таким образом ввод вы никак не учитываете то, что все символы имеют разную ширину и в один и тот же блок может уместиться их разное количество. Таким образом вы ставите пользователей в неравное положение, когда один может написать условно 1000 знаков, а у другого вместится всего 900.

Ограничения на длину диктуются совсем не UI/UX, а балансом между потребностями пользователя и прогнозированием места и железа, которое будет занимать эти описания при хранении. Когда речь идет о десятках миллионов пользователей, длина каждой строки сохраненной в базе имеет весомое значение.

вы ставите пользователей в неравное положение, когда один может написать условно 1000 знаков, а у другого вместится всего 900

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

1111 РЫБА ....

А про длину строк и потребности железа - тут можно согласиться, но, опять же, как рассчитать размер блока - если под самые узкие символы, то широких в строке будет меньше, длина строки будет меньше, прогнозирование с запасом получится.

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

Разница существенно увеличивается с увеличением ограничения на длину. Попробуйте объяснить пользователям, почему они видят объявления с 10 000 знаков в описании, а сами могу написать максимум 9 000, например. У вас это не получится сделать. Вы получите кучу негатива и багрепортов от пользователей.

Решение с оверлеем — это классический пример костыля, когда у вас нет экспертизы/желания, чтобы сделать правильно.

- Решение не выносит никакой критики для адаптивности. На мобилках оно просто не будет работать.
- Размеры оверлея я всегда могу поправить руками и обойти валидацию в 2 клика
- Такую же валидацию должен уметь делать сервер, потому что клиентскую валидацию всегда можно обойти. Сервер не сможет сделать это никак, кроме как имея константу на количество знаков.

Про несправедливость, в которой кому-то достаётся больше символов - это да, это не учитывал.

Честно говоря, ни разу не размещал на авто объявления, только просматривал. Даже представить не могу пользователей, которые пишут 10к знаков в объявлении (многие рассказы заметно короче), да ещё и сравнивают их длину с другими, но мир полон чудес.

И вы всерьез беспокоитесь о том, будет ли база весить 100 гигабайт или 120? Наверняка ведь тексты вынесены в отдельные таблицы с партиционированием, возможно шардированием. И рядом поисковые индексы на sphinx или каком-то подобном движке, которые занимают места побольше, чем сами тексты.

Ну и если уж мы рассуждаем о костылях, то нельзя не упомянуть и велосипеды :) https://github.com/orling/grapheme-splitter

Даже представить не могу пользователей, которые пишут 10к знаков в объявлении (многие рассказы заметно короче)

Существуют продавцы, особенно профессиональные, которые используют описание по максимуму.

И вы всерьез беспокоитесь о том, будет ли база весить 100 гигабайт или 120?

Надо уметь прогнозировать требования к железу при изменениях в таких больших проектах. В наших реалиях речь идет далеко не о сотнях ГБ.

Ну и если уж мы рассуждаем о костылях, то нельзя не упомянуть и велосипеды :)

Решение в статье не позиционируется, как альтернатива библиотеке. Я рассматриваю проблему и привожу примеры, как с ней можно бороться. В своем проекте вы можете использовать для решения этой проблемы вышеописанную библиотеку, если считаете это целесообразным.

Не хватает символов в объявлении и хотите запихать в него войну и мир? Легко: countGraphemes('В‍о‍й‍н‍а‍ ‍и‍ ‍м‍и‍р‍!‍!') = 1

Попробуйте объяснить пользователям, почему они видят объявления с 10 000 знаков в описании,

Так описание будет про размер окна, а не про 10 тыщ знаков :).

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

Техническая реализация может быть разной, не обязательно оверлеи, просто проверку реализовать по принципу влазит ли текст в окно (вообще условное, 1000 х 1000 пикселей например) один раз, а отрисовывать на устройстве уже дальше.

Перечитайте мои объяснения еще раз, пожалуйста. Проверки делать по принципу "сколько влезет" нельзя. У каждого пользователя должно быть четкое понимание, сколько знаков он может использовать. При этом каждый пользователь должен иметь идентичные возможности. А сервер должен уметь также проверять ограничения.

Ну и вы ничем не подкрепили утверждение, что с увеличением количества символов разница будет расти, напротив, она скорее будет уменьшаться, чисто статистически.

Чем больше символов разной ширины можно напечатать на условном листе, тем больше вариантов комбинаций с разным количеством символов может быть, тем больше будет разрыв между минимальным и максимальным количеством символов.

Да я понимаю ваши обьяснения, и реализация подхода вызывает уважение.

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

Пользователь оперирует не знаками, а абстракциями более высокого порядка - словами, предложениями, устойчивыми оборотами. Книга на 100 страниц может содержать роман, а может сборник стихов, количество знаков на порядки может отличаться, но на полке они будут занимать совершенно одинаковое место. Ограничение размером носителя - совершенно привычное бытовое, это формат бумаги, это размер тарелки, это площадь участка..

Ценность текста (и обявления в частности) не определяется количеством знаков, там более, если речь идет о порядках 10 тыс.

У вас кстати есть статистика по количеству знаков в обьявлениях? Среднее, медиана?

У вас кстати есть статистика по количеству знаков в обьявлениях? Среднее, медиана?

Такая статистика у нас конечно же имеется.

Пользователь оперирует не знаками, а абстракциями более высокого порядка 

Как раз именно знаками и оперирует пользователь. В особенности профессиональные пользователи, которые встречаются с такой механикой в любой системе.

Возьмите, например, копирайтеров, переводчиков и другие профессии, связанные с текстами в более классическом понимании. Они не берут оплату за страницу или слово. Объем работ и ценность считается по количеству знаков в тексте. Журналисты пишут статью на определенное количество знаков. Знак — универсальная едина измерения, потому что текст может быть воспроизведен на любом носителе, занимать разное количество страниц, экранов, чего угодно. Количество знаков в тексте останется неизменным.

Очень часто у переводчиков как раз оплата за страницы идет, а не за буквы.

Обычно, за слова, причём, может быть дифференциированно за новые и за известные слова (которые CAT-система сама правильно распознаёт).

Я больше не согласен, что главное именно знаки.

Часто есть расценки за страницу (стандартную - шрифт, интервалы) или слова или символы с пробелами на выбор и разница минимальная на большом тексте.

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

Мы здесь все-таки говорим о маленьких объемах текста и в области рекламы. Для пользователей, особенно профессиональных, важно, какое количество текста они могут разместить в свое объявлении. А количество знаков — самы универсальный показатель.

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

Хранение ведь в цифровом виде, а не в графическом.

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

А как насчёт тех пользователей, которым не нравятся куча эмодзи в тексте? Их интересы вы учли? Всё эти стрелочки вверх и восклицательные знаки безумно раздражают.

Количество железа зависит от количества байт. И если эмодзи тратит 8 байт, то в varchar (1000) ваша эмодзи уже не влазит и нужно резервировать 8000 байт, на случай если какой нить потребитель наберёт всё объявление тяжёлыми эмодзи.

Во вторых, количество железа зависит от среднего размера объявления, а не максимального.

И проблема выеденного яйца не стоит, ну набрал кто-то 442 символа, а не 450 и что? Т. е. Он пальчиком пересчитал символы, и ещё в поддержку письмо написал? Да ему санитара вызывать надо.

Уже писали что с введением любых символов юникода получается новый вектор обхода проверки объявлений на дубли? Теперь можно спрятать аудио наркотики за символами которые будут обходить черный список. Про аналитику по тексту объявлений тоже можно переживать. Как с этими моментами решили поступить?

Я не говорил, что мы разрешаем использовать любые символы юникода. Проверка на дубли работает совсем не по сравнению текста, а аналитика никак не страдает.

Теперь можно спрятать аудио наркотики за символами которые будут обходить черный список

Поясните, каким образом это связано?

Не в тему, конечно, на авито если поставить поиск в радиусе 1 км, то как в радиусе километра заканчивается, то следующее обяъявление сразу на камчатку, а потом в Белгороде. Да и сам фильтр скидывается. Указал радиус километр и стул, потом переделал на стул мягкий, он тебя сразу в новосиб отправляет. Вряд ли пользователь постоянно меняет своё положение? Можно предположить, читать он хотя бы одном городе остаётся? И если стул нужен в Москве то вряд ли ли стол нужен в Красноярске?

И это реально бесит, а вот количество символов в описании - это ни разу не считал)

К сожалению, я не знаю, как в деталях работает поиск. Обязательно передам ваш комментарий коллегам.

А можно было вместо фразы "Введите 250 символов" написать "Введите примерно 250 символов" и вопросов бы не было. А если без шуток, статья очень интересная, спасибо.

Можно попробовать напрмер ещё вот так:
Если есть в тексте код-поинт не из базовой плоскости - "втихаря" динамически накидывать в среднем +4 символа к стандартному ограничению. Типа по умолчанию разрешаем 250 символов.. но если есть один нестандартный код-поинт - разрешаем 254символа. Если присутствует два нестандартных кодпоинта - разрешаем 258символов, и т.д.

В принципе, тоже вариант, как другие, но подсчет будет не точный. Ведь любой символ не из bmp занимает две кодовые точки (суррогатные пары), а диакритические комбинации могут занимать сильно больше четырех.

Существует кодировка UTF-8, которая использует 8 бит на кодирование каждого символа. При помощи нее можно закодировать 256 различных знаков (2^8). Строки в этой кодировке занимают очень мало места: текст в 10 000 знаков будет занимать 10 000 байт или 9,77 КБ. Это позволяет оптимизировать использование папамяти.

Что я пропустил? Или санитары из заголовка просто отвлеклись?

Пояснение для ув. автора.

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

Кстати, в качестве курьёза. Кроме UTF-16 (16 бит) существует UCS-2 (2 байта, т.е. тоже 16 бит). Какая разница, спросит читатель? Только одна: UCS-2 не поддерживает суррогаты. Какая от этого польза - я не знаю.

UTF-8 позволяет использовать до 4 байтов. Количество байтов определяется необходимостью

Можете подсказать какой-нибудь материал по этому вопросу?

Кроме UTF-16 (16 бит) существует UCS-2

Я, откровенно говоря, не понял в каких случаях JS может использовать UCS-2 когда разбирался с темой.

Про UCS-2

Q: What is the difference between UCS-2 and UTF-16?

UCS-2 is obsolete terminology which refers to a Unicode implementation up to Unicode 1.1, before surrogate code points and UTF-16 were added to Version 2.0 of the standard. This term should now be avoided. UCS-2 does not describe a data format distinct from UTF-16, because both use exactly the same 16-bit code unit representations. However, UCS-2 does not interpret surrogate code points, and thus cannot be used to conformantly represent supplementary characters. Sometimes in the past an implementation has been labeled "UCS-2" to indicate that it does not support supplementary characters and doesn't interpret pairs of surrogate code points as characters. Such an implementation would not handle processing of character properties, code point boundaries, collation, etc. for supplementary characters.

А какой код у эмодзи "отца-одиночки с двумя детьми"?

Или он мессенджерами не будет восприниматься?

У этого эмодзи не одна кодовая точка. Он состоит из строки, в которой есть три базовых эмодзи, соединенных через ZWJ, а каждый базовый эмодзи состоит из суррогатной пары.

В мессенджере вы конечно можете его исспользовать ?‍?‍?.

А что с хранением в БД? Выходит, что для хранения строки 255 символов нужно закладывать в 8 раз больше места.

Место, занимаемое в БД зависит от реализации конкретной базы.
Не понял, почему в 8 раз больше?

Потому что один "символ" может занимать 8 байт?..

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

Спасибо! Отличная статья! Осталось написать таки свою опенсорс либу а-ля этот сегметер, чтобы на ноде и можно было)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий