Определить, является ли символ Unicode полной или половинной шириной в C++
Я пишу терминальное (консольное) приложение, которое должно обернуть произвольный текст в кодировке Unicode.
Терминалы обычно используют моноширинный шрифт (фиксированной ширины), поэтому для переноса текста это всего лишь подсчет символов и просмотр того, вписывается ли слово в строку или нет, и действуют ли они соответственно.
Проблема в том, что в таблице Unicode есть символы полной ширины, которые занимают ширину 2 символа в терминале.
Считая их, мы увидим 1 символ Юникода, но напечатанный символ имеет ширину в 2 "нормальных" (половинных) символа, что нарушает процедуру переноса, так как он не знает о символах, которые занимают вдвое большую ширину.
Например, это символ полной ширины (U+3004, символ JIS)
〄 12
Здесь он не занимает всю ширину в 2 символа, хотя он предварительно отформатирован, но он использует двойную ширину западного символа в терминале.
Чтобы справиться с этим, я должен различать символы полной и половинной ширины, но я не могу найти способ сделать это в C++. Действительно ли необходимо знать все символы полной ширины таблицы юникода, чтобы обойти проблему?
2 ответа
Вы должны использовать ICU u_getIntPropertyValue
с UCHAR_EAST_ASIAN_WIDTH
имущество.
Например:
bool is_fullwidth(UChar32 c) {
int width = u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH);
return width == U_EA_FULLWIDTH || width == U_EA_WIDE;
}
Обратите внимание, что если ваша графическая библиотека поддерживает комбинирование символов, вам придется учитывать их и при определении количества ячеек, используемых последовательностью; например e
с последующим U+0301
КОМБИНИРОВАНИЕ ОСТРОГО АКЦЕНТА займет всего 1 клетку.
Нет необходимости создавать таблицы, люди из Unicode уже сделали это:
http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
Тот же код используется в программном обеспечении эмуляции терминала, таком как xterm
[1], konsole
[2] и, скорее всего, другие...