Можете ли вы сделать мой терминал менее скучным?

11

Терминалы такие скучные в наши дни. Раньше они выглядели так:

Терминал 1 Терминал 2

Теперь они просто мягкие, скучные и черно-белые. Я хочу, чтобы вы написали мне программу, которая сделает мой терминал снова красочным!

Описание

Возьмите этот пример кода Ruby:

Пример кода

Большинство терминалов Linux поддерживают эти escape-последовательности ( \eрасшифровывается как escape-символ), и Windows может поддерживать их с помощью ANSICON . Вот синтаксис конкретной escape-последовательности, которая может изменить цвет текста или фона строки:

\e[{{COLOR}}m

где \eобозначает escape-символ ( 0x1Bв ASCII) и {{COLOR}}заменяется номером цвета, который вы хотите использовать (более подробно об этом позже). Текст, который следует после этой escape-последовательности, будет отформатирован в соответствии с указаниями, а значение 0сбрасывает все форматирование.

Ваша задача - взять строку с указанием текста, который может содержать цвет, и вывести его красочную версию.

Ввод, вывод

Нормальный текст работает так же, как обычный, и печатается буквально. Например, ввод wafflesдает тот же вывод, без специального цвета.

Синтаксис для указания цвета аналогичен синтаксису Википедии . Например, чтобы закрасить слова «красный цвет» в предложении красным цветом This is the color red!, введите:

This is {{red|the color red}}!

Цвет фона тоже работает. Если вы хотите черные буквы на белом фоне, вы должны использовать это:

{{black|white|This text is black on white}}

Чтобы получить только цвет фона, опустите передний план:

{{|red|This text has a red background}}

Технические характеристики

Две открытые фигурные скобки всегда указывают начало цветовой директивы . Две закрывающие фигурные скобки указывают конец. Скобки всегда будут совпадать; никогда не будет {{без соответствующего }}, и }}никогда не будет предшествовать его соответствующему {{. Эти цветовые директивы не будут вложенными, и {{никогда не будут появляться внутри цветовой директивы.

Внутри цветовой директивы всегда будет один или два |символа. Если он есть, то текст перед ним - это цвет переднего плана, а текст после - это строка, которая будет отображаться в этом цвете. Если их два, текст перед первым - это цвет переднего плана, текст после первого, но перед вторым - цвет фона, а текст после второго - строка для отображения. Эти вертикальные полосы могут существовать вне цветовой директивы и должны быть напечатаны буквально.

Цвет переднего плана или цвет фона (но не оба) могут быть пустыми, в этом случае вы должны оставить их по умолчанию. Последняя строка (которая выводится) никогда не будет пустой.

Вот инструкции для вывода текста определенного цвета:

  • Последовательность цветов определена в разделе «Описание». Например, цветовая последовательность 42 будет "\e[42m".

  • Чтобы установить цвет, напечатайте цветовую последовательность числа, определенного ниже:

     Color name   | Color sequence number (foreground / background)
    --------------+----------
     black        | 30 / 40
     red          | 31 / 41
     green        | 32 / 42
     yellow       | 33 / 43
     blue         | 34 / 44
     magenta      | 35 / 45
     cyan         | 36 / 46
     lightgray    | 37 / 47
     darkgray     | 90 / 100
     lightred     | 91 / 101
     lightgreen   | 92 / 102
     lightyellow  | 93 / 103
     lightblue    | 94 / 104
     lightmagenta | 95 / 105
     lightcyan    | 96 / 106
     white        | 97 / 107
    
  • Имена цветов чувствительны к регистру, и неверное имя цвета никогда не будет предоставлено. Вам не нужно обрабатывать такие вещи, как REDили lightgrey(пишется с e).

  • После того, как вы напечатаете цветовую последовательность, она будет применяться ко всему тексту, следующему за ней. Чтобы завершить цветовую последовательность (восстановить цвет по умолчанию), выведите цветовую последовательность 0( "\e[0m").

Прецедент

 {{|yellow|     }}
{{|yellow| }}     {{|yellow| }}
{{|yellow| }} {{red|'}} {{red|'}} {{|yellow| }}
{{|yellow| }} \_/ {{|yellow| }}
{{|yellow| }}     {{|yellow| }}
 {{|yellow|     }}

Это должно вывести смайлик ... со злыми красными глазами.

правила

  • Вы не можете использовать какие-либо библиотеки или функции вашего языка программирования для автоматического анализа цвета. Это значит, что именно вы должны определить, что это "red"значит; вы не можете иметь библиотеку, которая автоматически сделает это за вас.

  • Это , поэтому выиграет самый короткий код в байтах!

Дверная ручка
источник
На самом деле это должен быть терминал? Или просто красочная программа для просмотра текста? Это должно запускать команды?
Натан Меррилл
Мне трудно это проверить. Все, что я отправляю в STDOUT, используя указанный синтаксис, приходит в виде простого текста. В моем профиле bash используется цветное приглашение, поэтому я пытался украсть его \n\[\e[32m\]\w\n\[\e[0m\]> (зеленое имя каталога, обычное приглашение на следующей строке), но я не могу заставить его работать из программы (пока пробовал python и Java). Любые идеи?
Geobits
@ Geobits Попробуй echo -e "\e[31mtest\e[0m".
Дверная ручка
4
Я думаю, вам понравится lolcat.
Анко
1
Я думаю, что youон образно подразумевает your program(в отличие от вызова библиотечной функции), и что он принимает determineв смысле figure out, а не в choose. То есть именно ваша программа должна обрабатывать отображение: String ("red") | -> Integer (31). redтолько 31потому, что он так говорит, эта информация должна быть интегрирована в программу. Хотя можно утверждать, что именно это считается your program- можем ли мы использовать универсальные функции манипулирования строками? - не нагло обманывать / оскорблять.
Blutorange

Ответы:

6

Ruby, 205 189 188 186 185 182 174 170 165 161 159 154 байта

Размещение длинных строк с именами цветов в вашем коде не выглядит достаточно занудно.

До 170 отчасти благодаря rubik. Теперь полосы прокрутки исчезли!

Одно очевидное и одно не очень очевидное улучшение, благодаря гибкому ответу, без улучшения, я бы не пересмотрел это!

Теперь я сохранил 4 байта с помощью #sum. Я не собирался этого делать, но я только заметил, что это решение не учитывает регистр. Это счастливо обрабатывает {{RED|Red text}}.

Шестнадцатеричный дамп:

0000000: 7a3d 2d3e 6a7b 693d 2240 3054 2d44 1547  z=->j{i="@0T-D.G
0000010: 5155 0034 3256 2f46 1749 0b22 2e69 6e64  QU.42V/F.I.".ind
0000020: 6578 2028 415b 6a5d 2e74 6f5f 732e 7375  ex (A[j].to_s.su
0000030: 6d25 3839 292e 6368 723b 692b 3d69 3e39  m%89).chr;i+=i>9
0000040: 3f38 303a 3330 7d0a 243e 3c3c 243c 2e72  ?80:30}.$><<$<.r
0000050: 6561 642e 6773 7562 282f 7b7b 282e 2a3f  ead.gsub(/{{(.*?
0000060: 297d 7d2f 297b 413d 2431 2e73 706c 6974  )}}/){A=$1.split
0000070: 277c 273b 221b 5b25 693b 2569 6d23 7b41  '|';".[%i;%im#{A
0000080: 2e70 6f70 7d1b 5b30 6d22 255b 7a5b 305d  .pop}.[0m"%[z[0]
0000090: 2c31 302b 7a5b 315d 5d7d                 ,10+z[1]]}

Вы можете конвертировать его с xxd -r hex.dump.

Программа со всеми непечатными символами экранирована для справочных целей:

z=->j{i="@0T-D\x15GQU\x0042V/F\x17I\v".index (A[j].to_s.sum%89).chr;i+=i>9?80:30}
$><<$<.read.gsub(/{{(.*?)}}/){A=$1.split'|';"\x1b[%i;%im#{A.pop}\x1b[0m"%[z[0],10+z[1]]}

Это одна строка. Используйте это так

ruby colors.rb -W0 < input.txt

-W0Флаг подавляет предупреждения , которые будут отправлены в stderrпротивном случае. Тем не менее, программа прекрасно работает без каких-либо флагов.

Выход:

выход

blutorange
источник
1
Ах, у меня была та же идея, но вы меня опередили! Я думаю , вы могли бы сохранить полукокс с основанием 35, модуль 98 и исключающим 1. Строки будет: '1?IYU_N[(\x0c\x16&",\x1f\x01'. Моя строка длиной 16, хотя. Я вижу, тебе 18 лет, так что тебе, вероятно, придется приспосабливаться.
Рубик
Спасибо. Два дополнительных байта предназначены для поддержки цветового кода 39/49, который устанавливает задний / задний цвет по умолчанию. Но спасибо за совет, я в настоящее время на работе, и я подумаю над этим, когда вернусь домой.
Blutorange
1
Ну, я заметил, что вы можете использовать только 35 и 36 (по крайней мере, int()функция Python не может превышать 36). Затем я попробовал все комбинации для модуля (от 2 до 10000, но в теории можно было бы расширить поиск по всему Unicode) и для xor, который я оставил небольшим (от 1 до 9). Тогда я считал приемлемыми результаты только те, которые не содержали повторяющихся символов.
Рубик
Да, это более или менее то, что я сделал также. Первоначально я ограничивал себя печатными символами, потому что это дает вам меньше головной боли и выглядит лучше. Но поскольку я уже использую байт 0x1e вместо escape-последовательности, я мог бы также использовать больше непечатаемых символов. Чтобы добиться печатных символов, я использовал x.to_i(base)%mod+offset. Затем я заменил +с ^, потому что хорошо, это выглядит кулер. Кроме этого, это излишне. Отбрасывание ^99и переход <<к +сохранению для большего количества байтов. Спасибо за совет, я бы не заметил иначе!
blutorange
4

Рубин, 329 байт.

h={};(y=0..15).each{|i|h[%w(black red green yellow blue magenta cyan lightgray darkgray lightred lightgreen lightyellow lightblue lightmagenta lightcyan white)[i]]=y.map{|j|[30,40].map{|k|k+i%8+i/8*60}}[i]}
loop{puts gets.gsub(/{{.+?}}/){|x|"\e[#{h[(g=x.scan(/[^{}|]+/))[0]][0]}m#{(g[2]? "\e[#{h[g[1]][1]}m":'')}#{g.last}\e[0m"}}
Алекс Дева
источник
Какая версия Ruby мне нужна для запуска? Я использовал ruby 2.1.2p95и бросить ошибку: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Рэй
Привет @ Ray, он работает в 2.0.0-p451. Я не пробовал это в 2.1.2. Здесь это работает как скрипт и здесь это работает в irb .
Алекс Дева
Работает, когда вы вводите текст вручную. Если вы это сделаете ruby colors.rb < input.txt, он будет продолжать цикл после того, как все входные данные были прочитаны. Затем getsвозвращается nil, у которого нет #gsubметода , что вызывает ошибку. Используйте $><<$<.readвместо loop{puts gets, это также короче; )
blutorange
Я только что проверил этот сценарий со смайликом (см. Вопрос и изображение из моего поста), и вокруг смайлика нет желтой рамки?
Blutorange
4

Flex (лексер) - 226 197 192 182 168 (или 166)

Чтобы уменьшить его до 166, измените его \33на фактический escape-символ.

 int z;p(i){printf("\33[%dm",i);}
%%
"{{" z=2;
[a-z]*\| if(!z)REJECT;~-yyleng&&p("062q00t03058ns7uo0p90r4"[*(int*)&yytext[yyleng>7?4:0]%131%27]-10*z);z--;
"}}" p(z=0);

Скомпилируйте и запустите:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input
RICi
источник
3

Питон - 351

import re,sys
R=range
E=lambda n,d=0:'\033[%dm'%(T[n]+d)if n else''
def P(m):f,b,t=m.groups();return'%s%s%s\033[0m'%(E(f),E(b,10),t)
x='!red!green!yellow!blue!magenta!cyan'.replace
T=dict(zip(('black'+x('!',' ')+' lightgray darkgray'+x('!',' light')+' white').split(),R(30,38)+R(90,98)))
print re.sub(r'{{(\w+)?\|?(\w+)?\|?(.+?)}}',P,sys.stdin.read())
луч
источник
1

Кобра - 496

Это может быть почти одно печатное заявление.

use System.Text.RegularExpressions
class P
    def main
        print Regex.replace(Console.readLine,r'\{\{('+(l=List<of String>(((m=' black red green yellow blue magenta cyan'.split).join(' ')+' lightgray darkgray'+m.join(' light')+' white').split))[1:].join('|')+r')?\|?('+l[1:].join('|')+r')?\|(.*?)\}\}',do(a as Match))
            return if(x=l.indexOf('[a.groups[1]]'),r'\e['+'[if(x>8,x+81,x+29)]m','')+if(y=l.indexOf('[a.groups[2]]'),r'\e['+'[if(y>8,y+91,y+39)]m','')+'[a.groups[3]]'+if(x+y,r'\e[0m','')
Οurous
источник
1

Python, 561

Читает текст для форматирования из стандартного ввода.

import re,sys
def p(f,b,t):
    p=''
    m='\033[%dm'
    if f!=0:p+=m%f
    if b!=0:p+=m%b
    return p+t+m%0
def c(n,b=0):
    s='black:30#red:31#green:32#yellow:33#blue:34#magenta:35#cyan:36#lightgray:37#darkgray:90#lightred:91#lightgreen:92#lightyellow:93#lightblue:94#lightmagenta:95#lightcyan:96#white:97'
    r=0
    for i in s.split('#'):
        (t,c)=i.split(':')
        if t==n:
            r=int(c)
            if b==1:r+=10
    return r
def r(m):
    i=m.groups()
    f=b=0
    if i[0]!='':f=c(i[0])
    if i[1]!=None:b=c(i[1],1)
    return p(f,b,i[2])
print re.sub('{{(\w*)\|(?:(\w*)\|)?([^}]+)}}',r,sys.stdin.read())
Sammitch
источник
2
Это слишком многословно, чтобы иметь is not Noneв Codegolf. Вы можете использовать !=None, например.
Рэй
Кроме того, в def p(f,b,t)ваш код будет брошено ZeroDivisionError. Все, что мод 0, невозможно.
бета-распад
@BetaDecay - это не целочисленное значение, а форматируемая строка.
Саммит
Я получаю недопустимые синтаксические ошибки при re.subзапуске этого
ArtOfCode
(поздний комментарий) Работает ли этот 499-байтовый код ?
Эрик Outgolfer