Как я могу узнать, поместится ли персонаж в сетку, а если нет, то сколько пробелов ему потребуется?

С ncurses, как я могу узнать, впишется ли определенный символ в сетку? Я предполагаю, что это зависит от шрифта, и совсем не уверен, как это сделать.

пример текста, отображаемого в эмуляторе терминала

Итак, в приведенном выше примере функция, которую я ищу, будет:

grid_spaces_per_char(L"字") => 2
grid_spaces_per_char(L"G") => 1
grid_spaces_per_char(L"????") => 2
grid_spaces_per_char(L"Q") => 1
grid_spaces_per_char(L"。") => 2

Мне нужно знать это, чтобы я мог реализовать перенос слов в приложении C++ Slack ncurses с поддержкой UTF-8.

Если это невозможно сделать только с помощью ncurses, что мне делать, чтобы получить эту информацию?


person Fredrick Brennan    schedule 22.10.2017    source источник


Ответы (2)


wcwidth — это только часть решения: ncurses расширяет управляющие символы (кроме пробелов) до двух символов. «Простой» способ сделать это — написать символ в окно, которое не отображается, и использовать положение до/после, чтобы найти фактическую ширину, которую ncurses будет использовать для видимого (refreshed). Окно может быть создано, использовано в качестве рабочей области и удалено, не влияя на то, что отображается на экране.

Этот метод используется в Lynx,

    /*
     * Determine the number of cells the given string would take up on the screen,
     * limited (in the case of wide characters) by the maxCells parameter.
     *
     * If the returnCellNum parameter is TRUE, return the number of cells;
     * otherwise, return the length (limited by the len parameter) of the prefix of
     * the string that fits in maxCells cells.
     */

а также программу ncurses-examples view, какие комментарии

    /*
     * Use the curses library for rendering, including tab-conversion.  This
     * will not make the resulting array's indices correspond to column for
     * lines containing double-width cells because the "in_wch" functions will
     * ignore the skipped cells.  Use pads for that sort of thing.
     */

Кстати:

  • wcwidthвыдает разные результаты в разных системах, и на самом деле они могут не соответствовать тому, что отображается на терминале. Это ограничение связано со способом введения стандартов, и вместо того, чтобы строить один поверх другого, существуют противоречивые интерпретации, неполная документация и т. д.

  • Он также должен (но, по-видимому, редко) зависеть от локали, поскольку некоторые символы имеют разную ширину в разных локалях. В xterm обе проблемы связаны с рисованием линий

    /*
     * Solaris 10 wcwidth() returns "2" for all of the line-drawing (page
     * 0x2500) and most of the geometric shapes (a few are excluded, just
     * to make it more difficult to use).  Do a sanity check to avoid using
     * it.
     */

и мягкие дефисы

        /*
         * Regarding the soft-hyphen aberration, see
         * http://archives.miloush.net/michkap/archive/2006/09/02/736881.html
         */
person Thomas Dickey    schedule 22.10.2017
comment
Спасибо, что нашли время ответить на мой вопрос :) Вы настоящая легенда, когда дело доходит до консольных приложений! Вы занимаетесь этим дольше, чем я живу, так что большое спасибо, что нашли время. - person Fredrick Brennan; 02.11.2017

Я сам нашел ответ, используя несколько разных ключевых слов — ответ заключается в использовании wcswidth или wcwidth из wchar.h.

Есть некоторые оговорки, например, Windows не включает эту функцию, и иногда она может быть устаревшей. Другие предостережения объяснены здесь и здесь.

person Fredrick Brennan    schedule 22.10.2017