LINUX.ORG.RU

Одна code point (или последовательность) == одна графема

 , ,


0

2

Здрасьте. Чтобы не было путаницы в терминологии - под графемой понимаю что-то рисуемое на экране, занимаемое ровно одно знакоместо. Нужен алгоритм, который принимает на вход utf-8 строку и выдаёт на выходе число, которое равно количеству знакомест, которые занимает данная строка будучи отрисованной в терминале.

Но тут подстава со всякими управляющими символами, например Tab, котороый займет некоторое число знакомест, лазить в кишках terminfo для определения этого числа я точно не хочу. Решил поступить проще - итерироваться по символам и проверять является ли символ управляющим и если да, то менять его на пробел. И вот здесь встает вопрос - есть ли управляющие символы выше ASCII диапазона, которые могуть выдать что-то в терминал занимающее более одного знакоместа? Т.е. речь идёт о том, что делать ли std::iscntrl(char_sym, get_locale()) напрямую или конвертить предварительно всю последовательность в wchar_t и уже потом тестить. Естественно, что первое проще, а может второе и вовсе смысла не имеет. Управляющие символы там точно есть (U+2028, например), но рисуется в терминале одним знакоместом.

Я уже почти созрел до того, чтобы закрыть для себя вопрос юникода навсегда и остановиться лишь на в ASCII в софте, по крайней мере до момента, пока не появится адекватная либа, а не ICU. Была зыбкая надежда на boost.locale, но оказалось, что тот же U+2028 она не считет управляющим (тогда как локаль созданная дефолтными с++ средствами считает)

    wchar_t w = L'\u2028';
    cout << std::boolalpha 
        << std::iscntrl(w, boost::locale::generator()("en_US.UTF-8")) << endl
        << std::iscntrl(w, std::locale("en_US.UTF-8")) << endl;

$ ./a.out
false
true

В общем вопросы к ней появились.


Ответ на: комментарий от kvpfs

в Юникоде один символ может быть изображён каноничным и неканоничным образом, скажем, буковка с диакритическими знаками как один codepoint, либо базовая буковка + отдельно диакритический знак. Нужно приводить к каноничному виду и потом считать.

Harald ★★★★★ ()
Ответ на: комментарий от Harald

Это да, тут проблем нет, итерироваться можно без проблем тем же boost.locale не парясь о композиции/декомпозиции вообще. Тут интересует другое - могу ли я нарваться на условную U+100500, которая при выводе на экран займет более одного знакоместа? Или некая комбинированная графема (с диакритическими знаками или ещё какой хренью), которая также займет несколько мест?

kvpfs ()
Ответ на: комментарий от kvpfs

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

kvpfs ()
Ответ на: комментарий от sjinks

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

Как же можно было все настолько усложнить … Я второй день бьюсь над элементарными текстовыми операциями.

kvpfs ()
Ответ на: комментарий от kvpfs

Видимо это должно работать:

wchar_t w = L'\u2028';
cout << std::boolalpha 
     << std::isprint(w, boost::locale::generator()("en_US.UTF-8")) << endl
     << std::isprint(w, std::locale("en_US.UTF-8")) << endl;
$ ./a.out
false
false

Осталось только понять - насколько целесообразно использовать wcwidth для первых символов комбинаций, если все непечатные символы я заменю на пробелы, бывают ли печатные графемы шире одного знакоместа?

kvpfs ()
Ответ на: комментарий от anonymous

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

kvpfs ()
Ответ на: комментарий от kvpfs

Как я мог сомневать, это же юникод … Какие же они наркоманы

int main()
{
	locale::global(locale(""));
	int i = 0;
	for (wchar_t w = 0; w < 150000; ++ w) {
		if (std::isprint(w, locale())) {
			if (wcwidth(w) > 1) {
				wcout << w << endl;
			}
		}
	}
	return 0;
}
$ ./a.out | wc
  70322   70321  309408

ну и там всякая многознаковая красота вроде

◽
◾
☔
☕
♈
♉
♊
♋
♌
♍
♎
♏
♐
♑
♒
♓
♿
⚓
⚡
⚪
⚫

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

kvpfs ()
Ответ на: комментарий от kvpfs

Если собираешься делать TUI, надо взять ncurses или аналогичную библиотеку.

Ещё есть классная книга от автора notcurses: https://nick-black.com/htp-notcurses.pdf — там есть ответы на все твои вопросы. Включая те, о которых ты ещё не подозреваешь.

anonymous ()

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

/0 авторы юникода наговнякали говностандарт и ты понимаешь его неправильно. Способа исправить их говняканье нету, мучайся и страдай.

peregrine ★★★★★ ()
Последнее исправление: peregrine (всего исправлений: 1)

ТС, а теперь тебя ждёт ещё одно чудное открытие, касательно знакомест (это уже не к юникоду, а к стандартам рендеринга, которые отдельно живут), есть символы нестандартной ширины, на 1,5 знакоместа, на 2 знакоместа и может на 0,5 знакоместа (точно не помню всё говно которое напридумывали)

peregrine ★★★★★ ()
Последнее исправление: peregrine (всего исправлений: 1)

Спасибо.

Я в итоге болт положил на этот Юникод, слишком переусложненная система, ещё и надо продумать/протестить поведение для справа-налево письма и ещё миллион моментов, на ICU смотреть страшно. Слишком ёпотно для обработки текста. Остановлюсь на ASCII наборе.

kvpfs ()
Ответ на: комментарий от peregrine

/0 авторы юникода наговнякали говностандарт и ты понимаешь его неправильно. Способа исправить их говняканье нету, мучайся и страдай.

Стандарт-то ох%енный, а причина страданий только в том что людишки наговнякали говноязычков и говнописьменностей.

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Скорей уж говноэмоджей. Проблемы со всякими умляутами и нормализацией, вроде как, особо и не проблемы (хотя тот ещё геморрой), но вот эти вот compound emoji - это просто, мать его, вывих мозга.

SkyMaverick ★★★ ()
Ответ на: комментарий от slovazap

Мне кажется, что имеет смысл сделать надстройку над юникодом, в которой только живые языки, без всяких композиций, один код поинт - полный символ. Более того - такой стандарт можно пересматривать и вычищать умершие языки. Если что-то очень специализированное со спец терминами на чем-нибудь мертвом или написать один раз и навеки, то можно кодировать в полном юникоде с гарантиями неизменности кодовых позиций в нем. А пересмотр облегченного Юникода раз лет в 30 - не больно. В конце концов - писали BOM в файлах, аналогично можно писать версию юникод_light_X.

Ну объективно - чем дальше во времени, тем меньше будет наблюдаться языковое разнообразие. К чему упираться и тащить этот легаси чемодан? Каждый себя и свою культуру считает центром вселенной, конечно, но можно придумать какой-нибудь объективный критерий «мертвости».

kvpfs ()

Используй ICU. Все используют ICU и ты используй. Ты же не будешь обновлять свой костыль с каждой новой версией юникода, а они будут.

fsb4000 ★★★★★ ()
Ответ на: комментарий от kvpfs

но можно придумать какой-нибудь объективный критерий «мертвости».

Во-первых, нельзя. Во-вторых, кто вообще говорит о мёртвых языках? Арабский в 2 раза распространённее русского, а китайский в 10 раз (ну или распространённее всех европейских языков вместе взятых). Ну и новый универсальный язык эмодзи который используют повсеместно.

Разрешаю вам вместе с ОП откатиться до ASCII - чем это вам не юникод лайт? Кириллица вам точно не нужна, вы же не считаете свою культуру центром вселенной.

А прогрессивное человечество просто давно не использует ущербные абстракции типа «знакоместо», соответственно и проблем с юникодом никаких не имеет.

slovazap ★★★★★ ()
Ответ на: комментарий от slovazap

Во-вторых, кто вообще говорит о мёртвых языках?

Я

Арабский в 2 раза распространённее русского, а китайский в 10 раз (ну или распространённее всех европейских языков вместе взятых). Ну и новый универсальный язык эмодзи который используют повсеместно.

Я где-то предложил вычеркнуть арабский или китайский? Вот наверное очень востребовано кипрское письмо датируемое 4 веком до н.э. https://en.wikipedia.org/wiki/Cypriot_syllabary. Кучу этого легаси без ручки можно оставить лишь в базовом Юникоде. Ещё нужно отметить, что делать композиции из код поинтов в облегченной версии Юникода нет никакой необходимости т.к. по данным из гугла в мире насчитывается около 7 тыс языков (видимо вместе с мертвыми), так вот каждому языку можно выделить по целому «Юникоду» в 150 тыс символов, в UTF-8 останется ещё целый неиспользуемый миллиард. А 150К это даже для китайцев много.

А прогрессивное человечество просто давно не использует ущербные абстракции типа «знакоместо», соответственно и проблем с юникодом никаких не имеет.

Моноширинные шрифты тебе тоже не нужны?

kvpfs ()
Ответ на: комментарий от kvpfs

Я где-то предложил вычеркнуть арабский или китайский?

Тогда какой поинт в твоём лайте? Я привёл их как пример того что без композитинга не обойтись в принципе, а что ты собрался экономить если не отказываться от композитинга? Кодепоинты? Это смешно.

slovazap ★★★★★ ()
Ответ на: комментарий от kvpfs

Моноширинные шрифты тебе тоже не нужны?

Кстати, ты в курсе что это ещё от шрифта зависит?

Кирилица вполне может требовать 2 знакоместа.

https://i.imgur.com/38UzSow.png

или нет:

https://i.imgur.com/pNPecO1.png

fsb4000 ★★★★★ ()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от slovazap

Видимо тут в терминологии расходимся - имелось в виду формирование символа через запись по формуле: <базовый символ> + <обвес всякий в виде диакритических знаков>, т.е. в полной нормализованной форме. В лайт версии не должно быть вот этого всего, каждый код поинт представляет законченный символ. Как уже говорил - на каждый язык можно выделить 150К символов, еще останется место в ютф-8. У тех же китайцев всего 50К иероглифов. Плюсь тенденция неизбежно будет на уменьшение «живых» языков, и набор будет рассматриваться лишь в сторону уменьшения.

kvpfs ()
Ответ на: комментарий от fsb4000

От шрифта зависит, конечно. Но когда я выбираю моноширинный шрифт, то ожидаю один символ в одном знакоместе. С Юникодом это не работает в моем терминале почему-то и все эти «какашки» занимают несколько позиций. Кириллица вроде норм, одно место занимает.

kvpfs ()
Ответ на: комментарий от kvpfs

Видимо тут в терминологии расходимся - имелось в виду формирование символа через запись по формуле: <базовый символ> + <обвес всякий в виде диакритических знаков>

Нет, мы не расходимся в терминологии. Куча современных языков непредставима в виде отдельных «законченных символов». У композитинга намного более широкое применение чем «обвес в виде диакритических знаков». Кое-где это единственный способ составления слов.

т.е. в полной нормализованной форме

Такой не существует. Есть NFD, NFC, NFKD, NFKC, вы о какой? Никакая из них не гарантирует отсутствия композитных символов в выхлопе. И в стандарте есть явное замечание что никакая из них не необратима и все теряют семантику.

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

Свои нервы при работе с текстом.

Первое что надо сделать чтобы сохранить нервы - это не начинать придумывать велосипеды потому что в текущих решениях «всё слишком сложно», сначала не разобравшись почему именно там всё сложно.

slovazap ★★★★★ ()
Ответ на: комментарий от kvpfs

Но когда я выбираю моноширинный шрифт, то ожидаю один символ в одном знакоместе.

Сколько пикселей под символ? Даже если выкинуть эмодзи, есть китайский с иероглифами типа 釁.

Хочешь под все символы одинаково, используй полноширинные символы: вместо ASCII FF01-FF5E. Правда кириллицы там нет…

monk ★★★★★ ()
Ответ на: комментарий от slovazap

<Нет, мы не расходимся в терминологии. Куча современных языков непредставима в виде отдельных «законченных символов». У композитинга намного более широкое применение чем «обвес в виде диакритических знаков». Кое-где это единственный способ составления слов.

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

Но моё мнение (с дивана) тем не менее не сильно изменилось - Юникод переусложнили фактически убив его этим, назрел Юникод+. Если построить его по следующим принципам:

  1. Каждая буква алфавитных языков имеет свой код поинт. Не могу написать условную ‘й’ несколькими способами.
  2. Для иероглифических языков комбинации допускаются, но код поинты в комбинации строго отстортированы в порядке возрастания порядкового номера, иначе символ невалиден.
  3. Любимые эмодзи. Вообще не надо пытаться стандартизировать эту хипстоту. Достаточно выделить «emoji block» размеров в 32 код поинта, поинты блока могут составлять комбинацию (в порядке возрастания), а это 4 млрд возможных вариантов. Значение каждой комбинации пусть определяется не юникодом, а шрифтами, что хотят, то и рисуют пусть в каждом кейсе. В итоге утвердится некоторый общепринятый набор, который также гибко сможет корректироваться «в народе». Сегодня там могут рисовать маску, завтра каску.

Это простая система, с которой можно легко работать, ничего больше там не надо.

kvpfs ()
Ответ на: комментарий от kvpfs

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

Сам понял, что сказать хотел?

И разнообразие систем письменности «алфавитными» и «иероглифическими» (по твоей узколобой терминологии) не исчерпывается. Даже арабская с её вариантами букв уже в твой манямирок не влезает, не говоря уж о всяких там индостанских абугидах.

anonymous ()
Ответ на: комментарий от anonymous

Даже арабская с её вариантами букв уже в твой манямирок не влезает

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

Жрешь любой дерьмо, что тебе дают без попытки рассуждать.

kvpfs ()