Czy możesz sprawić, by mój terminal był mniej nudny?

11

Terminale są teraz tak nudne . Kiedyś wyglądały tak:

Terminal 1 Terminal 2

Teraz są po prostu nijakie, nudne i czarno-białe. Chcę, żebyś napisał mi program, który sprawi, że mój terminal znów będzie kolorowy!

Opis

Weźmy przykładowy kod Ruby:

Przykładowy kod

Większość terminali Linuksa obsługuje te sekwencje specjalne ( \eoznacza znak zmiany znaczenia), a system Windows może je obsługiwać za pomocą ANSICON . Oto składnia określonej sekwencji zmiany znaczenia, która może zmienić kolor tekstu lub tła łańcucha:

\e[{{COLOR}}m

gdzie \eoznacza znak zmiany znaczenia ( 0x1Bw ASCII) i {{COLOR}}jest zastępowany numerem koloru, którego chcesz użyć (więcej szczegółów na ten temat później). Tekst pojawiający się po tej sekwencji ucieczki zostanie sformatowany zgodnie z zaleceniami, a wartość 0spowoduje zresetowanie całego formatowania.

Twoim wyzwaniem jest pobranie ciągu określającego tekst, który może zawierać kolor, i wydrukowanie jego kolorowej wersji.

Wejście wyjście

Normalny tekst działa tak jak normalnie i jest drukowany dosłownie. Na przykład dane wejściowe wafflesdają taką samą moc wyjściową, bez specjalnego koloru.

Składnia określania koloru jest podobna do składni Wikipedii . Na przykład, aby w zdaniu pokolorować słowa „kolor czerwony” na czerwono This is the color red!, dane wejściowe byłyby następujące:

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

Kolory tła też działają. Jeśli chcesz czarne litery na białym tle, skorzystaj z tego:

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

Aby uzyskać tylko kolor tła, pomiń pierwszy plan:

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

Specyfikacja

Dwa otwarte nawiasy klamrowe zawsze określają początek dyrektywy w sprawie kolorów . Dwa zamykające nawiasy klamrowe określają koniec. Nawiasy zawsze będą pasować; nigdy nie będzie {{bez odpowiednika }}, a }}nigdy nie przyjdzie przed jego odpowiednikiem {{. Te dyrektywy dotyczące kolorów nie zostaną zagnieżdżone i {{nigdy nie pojawią się w dyrektywie kolorów.

W dyrektywie kolorów zawsze będzie jeden lub dwa |symbole. Jeśli istnieje, tekst przed nim ma kolor pierwszego planu, a tekst po nim to ciąg znaków, który ma być wyświetlany w tym kolorze. Jeśli są dwa, tekst przed pierwszym jest kolorem pierwszego planu, tekst po pierwszym, ale przed drugim kolorem tła, a tekst po drugim to ciąg znaków do wyświetlenia. Te pionowe paski mogą istnieć poza dyrektywą dotyczącą kolorów i powinny być drukowane dosłownie.

Kolor pierwszego planu lub kolor tła (ale nie oba) mogą być puste, w takim przypadku należy pozostawić je jako domyślne. Ostatni ciąg (ten, który ma zostać wyprowadzony) nigdy nie będzie pusty.

Oto wskazówki, jak wydrukować tekst określonego koloru:

  • Sekwencji kolorów jest zdefiniowana w sekcji „Opis”. Na przykład sekwencja kolorów 42 "\e[42m".

  • Aby ustawić kolor, wydrukuj sekwencję kolorów liczby określonej poniżej:

     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
    
  • W nazwach kolorów rozróżniana jest wielkość liter i nigdy nie zostanie podana nieprawidłowa nazwa koloru. Nie trzeba obsłużyć rzeczy jak REDlub lightgrey(pisany ze związkiem e).

  • Po wydrukowaniu sekwencji kolorów będzie ona obowiązywać dla całego tekstu po niej. Aby zakończyć sekwencję kolorów (przywróć domyślny kolor), wypisz sekwencję kolorów 0( "\e[0m").

Przypadek testowy

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

To powinno wywołać uśmiechniętą twarz ... ze złymi czerwonymi oczami.

Zasady

  • Nie można używać żadnych bibliotek ani funkcji języka programowania do automatycznego analizowania koloru. Oznacza to, że musisz być tym, który określa, co "red"oznacza; nie możesz mieć biblioteki, która zrobi to automatycznie.

  • To jest , więc wygra najkrótszy kod w bajtach!

Klamka
źródło
To rzeczywiście ma być terminal? A może po prostu kolorowa przeglądarka tekstu? Czy ma uruchamiać polecenia?
Nathan Merrill
Trudno mi to przetestować. Wszystko, co wysyłam do STDOUT przy użyciu określonej składni, ma postać zwykłego tekstu. Mój profil bash używa kolorowego monitu, więc wykradam się od tego, co próbowałem \n\[\e[32m\]\w\n\[\e[0m\]> (zielona nazwa katalogu, zwykły monit w następnym wierszu), ale nie mogę go uruchomić z programu (jak dotąd wypróbowałem Python i Javę). Jakieś pomysły?
Geobits
@Geobits Try echo -e "\e[31mtest\e[0m".
Klamka
4
Myślę, że ci się spodoba lolcat.
Anko
1
Myślę, że w youprzenośni oznacza on your program(w przeciwieństwie do wywołania funkcji bibliotecznej) i że determinerozumie to figure out, a nie jak choose. Tj. To twój program powinien obsługiwać mapowanie: String („red”) | -> Integer (31). dzieje się tak redtylko 31dlatego, że tak mówi, informacja ta musi zostać włączona do programu. Chociaż można argumentować, co by się liczyło your program- czy możemy używać funkcji manipulacji ciągami ogólnego przeznaczenia? - nie rażąco oszukiwać / nadużywać.
blutorange

Odpowiedzi:

6

Rubinowy, 205 189 188 186 185 182 174 170 165 161 159 159 154 bajtów

Umieszczanie długich ciągów nazw kolorów w kodzie nie wygląda na dość nerdy.

Do 170 częściowo dzięki rubik. Teraz zniknęły paski przewijania!

Jedna oczywista i jedna nie tak oczywista poprawa, dzięki elastycznej odpowiedzi, bez poprawy, nie wróciłbym do tego!

Już nie, zapisałem 4 bajty za pomocą #sum. Nie zamierzałem tego, ale zauważyłem, że w tym rozwiązaniu nie jest rozróżniana wielkość liter. Szczęśliwie przetwarza {{RED|Red text}}.

Zrzut szesnastkowy:

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]]}

Możesz to przekonwertować za pomocą xxd -r hex.dump.

Program ze wszystkimi znakami, których nie można wydrukować, uciekł w celach referencyjnych:

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]]}

To jest jedna linia. Użyj tego w ten sposób

ruby colors.rb -W0 < input.txt

-W0Flag pomija ostrzeżenia, które będą wysyłane do stderrinaczej. Jednak program działa dobrze bez żadnych flag.

Wynik:

wynik

blutorange
źródło
1
Ach, miałem ten sam pomysł, ale pobiłaś mnie! Myślę, że można zaoszczędzić char z bazy 35, moduł 98 i xor 1. Ciąg będzie: '1?IYU_N[(\x0c\x16&",\x1f\x01'. Mój ciąg ma jednak długość 16. Widzę, że twój ma 18 lat, więc prawdopodobnie musisz się dostosować.
rubik
Dzięki. Dwa dodatkowe bajty służą do obsługi kodu koloru 39/49, który ustawia domyślny kolor back / forground. Ale dzięki za napiwek, jestem obecnie w pracy i zastanowię się, kiedy wrócę do domu.
blutorange
1
Zauważyłem, że jedynymi bazami, których możesz użyć, są 35 i 36 (przynajmniej int()funkcja Pythona nie może przekroczyć 36). Następnie wypróbowałem wszystkie kombinacje dla modułu (od 2 do 10000, ale teoretycznie można rozszerzyć wyszukiwanie na cały Unicode) i dla xora, który zachowałem mały (1 do 9). Następnie uznałem za akceptowalne wyniki tylko te, które nie zawierały zduplikowanych znaków.
rubik
Tak, mniej więcej to zrobiłem. Początkowo ograniczałem się do postaci do wydrukowania, ponieważ daje to mniejszy ból głowy i wygląda ładniej. Ale ponieważ już używam bajtu 0x1e zamiast sekwencji ucieczki, równie dobrze mogę użyć większej liczby znaków, które nie mogą zostać wydrukowane. Użyłem, aby uzyskać znaki do wydrukowania x.to_i(base)%mod+offset. Następnie otrzymuje +się ^, bo dobrze, wygląda chłodniej. Poza tym nie jest to konieczne. Upuszczanie ^99i zmiana <<na +zapisane dla większej liczby bajtów. Dzięki za wskazówkę, inaczej bym tego nie zauważył!
blutorange
4

Rubinowy, 329 bajtów.

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"}}
Alex Deva
źródło
Jakiej wersji Ruby potrzebuję, aby to uruchomić? Kiedyś ruby 2.1.2p95i rzucać błąd: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray
Cześć @ Ray, działa w wersji 2.0.0-p451. Nie próbowałem tego w 2.1.2. Tutaj działa jak skrypt i tutaj działa w IRB .
Alex Deva,
Działa, gdy wpisujesz tekst ręcznie. Jeśli to zrobisz ruby colors.rb < input.txt, będzie on zapętlał po odczytaniu wszystkich danych wejściowych. Następnie getszwraca nil, która nie posiada #gsubmetody, co powoduje błąd. Użyj $><<$<.readzamiast loop{puts gets, jest również krótszy; )
blutorange
Właśnie przetestowałem ten skrypt z uśmiechniętą buźką (patrz pytanie i zdjęcie z mojego postu), a wokół uśmiechu nie ma żółtej ramki?
blutorange
4

Flex (Lexer) - 226 197 192 182 168 (lub 166)

Aby sprowadzić go do 166, zmień \33postać na ucieczkę.

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

Skompiluj i uruchom:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input
rici
źródło
3

Python - 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())
Promień
źródło
1

Kobra - 496

Może to być prawie pojedyncza instrukcja drukowania.

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','')
Obrzydliwe
źródło
1

Python, 561

Odczytuje tekst do sformatowania ze standardowego wejścia.

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
źródło
2
Jest zbyt gadatliwy, aby mieć go is not Nonew golfie. Możesz użyć !=Nonena przykład.
Ray
Ponadto w def p(f,b,t)twoim kodzie wyrzuci się ZeroDivisionError. Cokolwiek mod 0 jest niemożliwe.
Rozpad
@BetaDecay to nie jest liczba całkowita modulowana, to formatowany ciąg.
Sammitch,
Otrzymuję nieprawidłowe błędy składniowe podczas re.suburuchamiania tego
ArtOfCode
(późny komentarz) Czy ten 499-bajtowy kod działa?
Erik the Outgolfer