Как остановить Ansi Color Codes, во внимание выравнивание PrintF?
-
03-10-2019 - |
Вопрос
Я обнаружил это при использовании Ruby Printf, но это также относится к печати C.
Если вы включите код побега ANSI в выходной строке, он посылает выравнивание.
Рубин:
ruby-1.9.2-head > printf "%20s\n%20s\n", "\033[32mGreen\033[0m", "Green"
Green # 6 spaces to the left of this one
Green # correctly padded to 20 chars
=> nil
Та же линия в программе C производит тот же выход.
Есть ли в любом случае, чтобы получить printf (или что-то еще), чтобы выровнять вывод и не добавлять пробелы для непечатанных символов?
Это ошибка, или есть хорошая причина для этого?
Обновлять: Поскольку printf нельзя полагаться, чтобы выровнять данные, когда есть коды ANSI и широкие символы, есть ли лучшая практика способ выстраивания цветных табличных данных в консоли в Ruby?
Решение
Я не согласен с вашей характеристикой 9 пробелов после зеленого зеленого цвета ». Я использую Perl, а не Ruby, но если я использую модификацию вашего заявления, печатаю символ трубы после строки, я получаю:
perl -e 'printf "%20s|\n%20s|\n", "\033[32mGreen\033[0m", "Green";'
Green|
Green|
Это показывает мне, что printf()
Заявление подсчитала 14 символов в строке, поэтому он предпринимает 6 пробелов для выравнивания на 5 символов. Однако терминал проглотил 9 из этих символов, интерпретируя их как изменения цвета. Итак, вывод появился 9 символов короче, чем вы этого хотели. Однако printf()
не печатал 9 пробелов после первого «зеленого».
Что касается лучших практик для выровненного выхода (с колоризацией), я думаю, вам понадобится в поле каждого размера и выровненного поля, окруженного простыми полями «% s», которые касаются колоризации:
printf "%s%20.20s%s|%s%-10d%s|%s%12.12s%s|\n",
co_green, column_1_data, co_plain,
co_blue, column_2_data, co_plain,
co_red, column_3_data, co_plain;
Где, очевидно, co_XXXX
Переменные (константы?) содержат последовательности эвакуации для переключения на именованный цвет (и co_plain
может быть лучше, как co_black
). Если получается, что вам не нужна колоризация на каком-то поле, вы можете использовать пустую строку вместо co_XXXX
переменные (или называть это co_empty
).
Другие советы
Это не ошибка: нет пути Ruby должны знать (по крайней мере, в Printf, это была бы другая история для чего-то вроде проклейки), что его stdout собирается в терминал, который понимает, что escape VT100.
Если вы не корректируете фоновые цвета, что-то вроде этого может быть лучшей идеей:
GREEN = "\033[32m"
NORMAL = "\033[0m"
printf "%s%20s%s\n", GREEN, "Green", NORMAL
printf
Спецификаторы ширины поля не полезны для выравнивания табличных данных, элементов интерфейса и т. Д. Помимо вопроса о контрольных символах, которые вы уже обнаружили, существуют также неразмерные и двухшимальные символы, которые ваша программа должна иметь дело, если вы не будете T Хотите ограничить вещи на устаревшие кодировки символов (которые многие пользователи считают устаревшим).
Если вы настаиваете на использовании printf
Таким образом, вам, вероятно, нужно сделать что-то вроде:
printf("%*s\n%*s\n", bytestopad("\033[32mGreen\033[0m", 20), "\033[32mGreen\033[0m", bytestopad("Green", 20), "Green");
куда bytestopad(s,n)
Является ли функцией, которую вы пишете, что вычисляет, сколько общих байтов нужны (строки плюс пробелов на добивках), чтобы привести к строке s
взяться за n
Колонны терминалов. Это будет включать разборки сбежаков и обработки многобайтовых персонажей и используя объект (например, POSIX wcwidth
Функция) Чтобы найти, сколько столбцов терминалов каждый берет. Обратите внимание на использование *
на месте постоянного поля ширины в printf
Формат строки. Это позволяет вам пройти int
аргумент printf
Для ширины поля времени выполнения.
Я бы отделил любые эскогальные последовательности от фактического текста, чтобы избежать целого вопроса.
# in Ruby
printf "%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green"
или
/* In C */
printf("%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green");
Поскольку Ansi Escape Sequelles не является частью Ruby, либо C, не считает, что им нужно относиться к этим персонажам особенным и по праву.
Если вы собираетесь делать множество цветов терминала, то вам следует рассмотреть курсоры и NCurses, которые предоставляют функции для изменений цвета, которые работают для многих различных типов клемм. Они также обеспечивают гораздо больше возможностей, таких как текстовые окна, функциональные клавиши, а иногда и даже взаимодействие мыши.
Вот решение, с которой я придумал недавно. Это позволяет использовать color("my string", :red)
в printf
утверждение. Мне нравится использовать одну и ту же строку форматирования для заголовков и данных - сухой. Это делает это возможным. Кроме того, я использую радуга GEM для генерации цветовых кодов; Это не идеально, но делает работу. То CPAD
Хеш содержит два значения для каждого цвета, соответствующие левой и правой прокладке соответственно. Естественно, это решение должно быть расширено, чтобы облегчить другие цвета и модификаторы, такие как жирные и подчеркивание.
CPAD = {
:default => [0, 2],
:green => [0, 3],
:yellow => [0, 2],
:red => [0, 1],
}
def color(text, color)
"%*s%s%*s" % [CPAD[color][0], '', text.color(color), CPAD[color][1], '']
end
Пример:
puts "%-10s %-10s %-10s %-10s" % [
color('apple', :red),
color('pear', :green),
color('banana', :yellow)
color('kiwi', :default)
]