Чи можете ви зробити мій термінал менш нудним?


11

На сьогодні термінали такі нудні . Вони раніше виглядали так:

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

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

Опис

Візьмемо цей приклад код Ruby:

Приклад коду

Більшість терміналів Linux підтримують ці послідовності евакуації ( \eозначає символи втечі), а Windows може підтримувати їх за допомогою ANSICON . Ось синтаксис конкретної послідовності евакуації, який може змінити колір тексту або фону рядка:

\e[{{COLOR}}m

де \eстоїть символ втечі ( 0x1Bв ASCII) і {{COLOR}}замінюється номером кольору, який ви хочете використовувати (детальніше про це пізніше). Текст, що надходить після цієї послідовності евакуації, буде відформатований відповідно до вказівок, а значення " 0" скине все форматування.

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

Введення-виведення

Звичайний текст працює як звичайний, і друкується буквально. Наприклад, вхід wafflesдає той самий вихід, без особливого кольору.

Синтаксис для визначення кольору схожий на синтаксис Wikipedia . Наприклад, щоб пофарбувати слова "кольоровий червоний" у червоне в реченні 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 за допомогою вказаного синтаксису, виходить у простому тексті. У моєму баш-профілі використовується кольорова підказка, тому я викрадаю те, що я спробував \n\[\e[32m\]\w\n\[\e[0m\]> (зелена назва каталогів, звичайна підказка в наступному рядку), але я не можу змусити його працювати з програми (пробував python та Java поки що). Будь-які ідеї?
Геобіт

@Geobits Спробуйте echo -e "\e[31mtest\e[0m".
Дверна ручка

4
Я думаю, вам сподобалося б lolcat.
Анко

1
Я думаю, що youвін образно означає your program(на відміну від заклику до функції бібліотеки), і що він приймає determineв сенсі figure out, а не як в choose. Тобто саме ваша програма повинна обробляти відображення: String ("червоний") | -> Integer (31). redце лише 31тому, що він говорить так, що інформацію потрібно інтегрувати в програму. Хоча, можливо, можна стверджувати, що саме вважатиметься your program- чи можемо ми використовувати функції маніпулювання рядком загального призначення? - не нахабно обманюйте / не зловживайте.
blutorange

Відповіді:


6

Рубі, 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іншому випадку. Однак програма працює чудово, без будь-яких прапорів.

Вихід:

вихід


1
Ах, у мене була така ж ідея, але ти мене до цього побив! Я думаю , ви могли б зберегти напівкокс з підставою 35, модуль 98 і виключає 1. Рядки буде: '1?IYU_N[(\x0c\x16&",\x1f\x01'. Моя рядок - 16, хоча. Я бачу, що у вас 18 років, тому вам, мабуть, доведеться коригуватися.
rubik

Дякую. Два додаткових байти знаходяться для підтримки кольорового коду 39/49, який встановлює стандартний колір заднього / переднього плану. Але дякую за пораду, я зараз на роботі, і я ще раз подумаю, коли повернусь додому.
blutorange

1
Я помітив, що єдиними базами, якими ви можете скористатися, є 35 та 36 (принаймні int()функція Python не може перевищувати 36). Тоді я спробував усі комбінації для модуля (від 2 до 10000, але теоретично можна було розширити пошук на весь Unicode) і для xor, який я мав невеликий (1 до 9). Тоді я вважав прийнятними результати лише тих, які не містили дублюючих символів.
rubik

Так, це більш-менш те, що я і зробив. Спочатку я обмежувався персонажами для друку, тому що це дає вам менше головного болю і виглядає приємніше. Але оскільки я вже використовую байт 0x1e замість послідовності евакуації, я можу також використовувати більше символів, які не можна друкувати. Для досягнення символів для друку я використовував 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фактичний символ втечі.

 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

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','')

1

Пітона, 561

Читає текст у форматі від stdin.

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())

2
Це занадто багатослівний, щоб мати is not Noneв кодовому гольфі. Ви можете використовувати !=None, наприклад.
Рей

Крім того, у def p(f,b,t)вашому коді буде викинуто ZeroDivisionError. Що-небудь mod 0 неможливо.
Бета-розпад

@BetaDecay це не ціле число, яке модулюється, це формат рядка.
Саммітч

Я отримую недійсні синтаксичні помилки при re.subвиконанні цього
ArtOfCode

(пізній коментар) Чи працює цей 499-байтний код ?
Ерік Аутгольфер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.