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

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

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 ★★
() автор топика
Ответ на: комментарий от 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

бывают ли печатные графемы шире одного знакоместа

Бывают, CJK в основном.

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

Телефон их все отображает как одноместные глифы.

static_lab ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.