ANSI-коды
Есть много программ, печатающих что-нибудь в терминал. Но их можно сильно разнообразить: можно покрасить текст, двигать курсор или переписать какой-нибудь текст поверх старого. Благодаря этому в Git красивые прогресс-бары, а Vim и Nano позволяют редактировать текст внутри терминала, как будто это происходит в обычном блокноте.
Существуют библиотеки, которые помогают в такой работе с терминалом. Но куда круче научиться делать это самостоятельно. В этой статье мы рассмотрим, что можно сделать простой командой print
в Python.
Большинство программ взаимодействуют с терминалом через управляющие коды ANSI. Это специальные инструкции для терминала. В терминалах разных систем поддерживаются разные коды. В Википедии есть список поддерживаемых кодов. В этой статье мы научимся работать с терминалами Unix систем: Ubuntu или OS-X. На Windows такие команды поддерживаются только в Windows Terminal, в обычном cmd
они не работают.
Покраска текста
Начнём с простого вывода в консоль. Так выглядит обычный, не покрашенный текст:
Чтобы покрасить текст, нужно в придачу вывести пару ANSI-кодов. Вот два ваших первых ANSI-кода:
- Красный текст:
\u001b[31m
- Вернуть как было:
\u001b[0m
Вот как их применять:
Покрасилась не только фраза Hello, World!
, но и всё что под ней. На первой строчке терминал получил команду “Теперь выводи всё красным”. Дальше он выводил весь текст красным, пока не получил команду “Верни как было”: \u001b[0m
.
Чтобы получилось аккуратно, лучше ставить команду “Верни как было” сразу после фразы:
С этим разобрались, а как ещё можно красить? У большинства терминалов есть 8 базовых цветов:
Цвет | Код |
---|---|
Чёрный | \u001b[30m |
Красный | \u001b[31m |
Зелёный | \u001b[32m |
Жёлтый | \u001b[33m |
Синий | \u001b[34m |
Пурпурный | \u001b[35m |
Голубой | \u001b[36m |
Белый | \u001b[37m |
Сброс цвета | \u001b[0m |
Чтобы сделать цвет ярче, можно прибавить к коду ;1
. Получается ещё 8 цветов:
Цвет | Код |
---|---|
Яркий чёрный | \u001b[30;1m |
Яркий красный | \u001b[31;1m |
Яркий зелёный | \u001b[32;1m |
Яркий жёлтый | \u001b[33;1m |
Яркий синий | \u001b[34;1m |
Яркий пурпурный | \u001b[35;1m |
Яркий голубой | \u001b[36;1m |
Яркий белый | \u001b[37;1m |
Сброс цвета | \u001b[0m |
Все цвета
Всего в ANSI 256 цветов. Они составляются так: \u001b[38;5;КОДm
, где вместо КОД
— число от 0 до 255:
Покраска фона
Работает так же, только коды другие:
Цвет | Код |
---|---|
Чёрный | \u001b[40m |
Красный | \u001b[41m |
Зелёный | \u001b[42m |
Жёлтый | \u001b[43m |
Синий | \u001b[44m |
Пурпурный | \u001b[45m |
Голубой | \u001b[46m |
Белый | \u001b[47m |
Сброс цвета такой же: \u001b[0m
.
Либо можно собрать один из 256 доступных по схеме \u001b[48;5;КОДm
, где вместо КОД
— число от 0 до 255:
Навигация курсора
Курсор – это вот эта “мигающая палочка”, откуда набирается текст:
Если продолжить набирать текст в примере выше, то он будет набираться между словами “вот” и “эта”.
Вывод в терминале тоже набирает “курсор”. Вот как он выглядит:
Вы можете двигать обычный курсор просто кликнув мышью в нужное место. В терминале так не получится, для этого есть отдельные ANSI-коды::
Направление | Код |
---|---|
Вверх | \u001b[ШАГA |
Вниз | \u001b[ШАГB |
Вправо | \u001b[ШАГC |
Влево | \u001b[ШАГD |
Вместо ШАГ
нужно подставить нужное число, например, \u001b[10A
— переведёт курсор на 10 строк вверх. Вот так это выглядит:
Мы вывели код, который поднимает курсор терминала на 4 строчки вверх. Поэтому следующий текст вывелся поверх того, что уже был выведен на третьей строчке.
Заметьте, что сам курсор в итоге оказался на следующей строке. Дело тут в том, что print
добавляет перенос строки:
Каждый новый принт выводит строку, потом ставит перенос строки. Если выводить нечего, он выводит только перенос строки.
Это можно отключить:
Теперь первый print()
перенос не вывел, курсор не сдвинулся вниз, поэтому вторая строка вывелась прямо следом за первой же.
Очистка экрана
Перемещение курсора по экрану позволяет выводить один текст поверх другого, но это не всегда просто сделать:
print('Первая надпись на экране')
print('Это вторая надпись на экране')
print('\u001b[2A')
print('Третья надпись')
В результате получим абракадабру. Одна надпись наложилась поверх другой, но не затерла её полностью:
Первая надпись на экране
Третья надписьпись на экране
Эту проблему можно решить добавлением пробелов к коротким строкам, чтобы все получились одной ширины:
print('Первая надпись на экране')
print('Это вторая надпись на экране')
print('\u001b[2A')
print('Третья надпись ')
Это работает, но очень неудобно: сложно менять текст сообщений и легко ошибиться с количеством пробелов. Если вы можете себе позволить очистить экран полностью, то воспользуйтесь спец.символом для очистки экрана '\033[2J'
:
print('Это первая надпись на экране')
print('\033[2J') # очистит экран
print('Вторая надпись')
Теперь всё будет работать как надо:
Вторая надпись
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.