Puoi rendere il mio terminale meno noioso?


11

I terminali sono così noiosi in questi giorni. Sembravano così:

Terminale 1 Terminale 2

Ora sono solo insipidi e opachi e in bianco e nero. Voglio che tu mi scriva un programma che renderà di nuovo tutto il mio terminale colorato!

Descrizione

Prendi questo esempio di codice Ruby:

Codice di esempio

La maggior parte dei terminali Linux supporta queste sequenze di escape ( \erappresenta il carattere di escape) e Windows può supportarle con ANSICON . Ecco la sintassi della specifica sequenza di escape che può cambiare il testo o il colore di sfondo di una stringa:

\e[{{COLOR}}m

dove \esta per il carattere di escape ( 0x1Bin ASCII) e {{COLOR}}viene sostituito dal numero del colore che si desidera utilizzare (maggiori dettagli su quello successivo). Il testo che segue questa sequenza di escape verrà formattato come indicato e un valore di 0reimposterà tutta la formattazione.

La tua sfida è quella di prendere una stringa specificando del testo che può contenere colore e produrre una versione colorata di esso.

Input Output

Il testo normale funziona esattamente come il normale e viene stampato letteralmente. Ad esempio, l'input wafflesproduce lo stesso output, senza colori speciali.

La sintassi per specificare un colore è simile alla sintassi di Wikipedia . Ad esempio, per colorare le parole "il colore rosso" in rosso nella frase This is the color red!, l'input sarebbe:

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

Anche i colori di sfondo funzionano. Se volessi lettere nere su uno sfondo bianco, dovresti usare questo:

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

Per ottenere solo un colore di sfondo, ometti il ​​primo piano:

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

specificazione

Due parentesi graffe aperte specificano sempre l'inizio di una direttiva colore . Due parentesi graffe di chiusura specificano la fine. Le parentesi corrisponderanno sempre; non ci sarà mai un {{senza un corrispondente }}, e un }}non verrà mai prima del suo corrispondente {{. Queste direttive sul colore non verranno annidate e {{non appariranno mai all'interno di una direttiva sul colore.

All'interno di una direttiva colore, ci saranno sempre uno o due |simboli. Se ce n'è uno, il testo che precede è il colore di primo piano e il testo che segue è la stringa da mostrare in quel colore. Se ce ne sono due, il testo prima del primo è il colore di primo piano, il testo dopo il primo ma prima del secondo è il colore di sfondo e il testo dopo il secondo è la stringa da visualizzare. Queste barre verticali possono esistere al di fuori di una direttiva sui colori e devono essere stampate letteralmente.

Il colore di primo piano o di sfondo (ma non entrambi) potrebbe essere vuoto, nel qual caso dovresti lasciarli come predefiniti. La stringa finale (quella da emettere) non sarà mai vuota.

Ecco le indicazioni per l'output del testo di un determinato colore:

  • Una sequenza di colori è definita nella sezione "Descrizione". Ad esempio, una sequenza di colori di 42 sarebbe "\e[42m".

  • Per impostare un colore, stampare la sequenza di colori del numero determinato di seguito:

     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
    
  • I nomi dei colori fanno distinzione tra maiuscole e minuscole e non verrà mai fornito un nome di colore non valido. Non devi gestire cose come REDo lightgrey(scritte con un e).

  • Dopo aver stampato una sequenza di colori, verrà applicata per tutto il testo che la segue. Per terminare una sequenza di colori (ripristina il colore predefinito), genera una sequenza di colori di 0( "\e[0m").

Caso di prova

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

Questo dovrebbe produrre una faccina sorridente ... con malvagi occhi rossi.

Regole

  • Non è possibile utilizzare alcuna libreria o funzione del proprio linguaggio di programmazione per analizzare automaticamente un colore. Ciò significa che devi essere tu a determinare cosa "red"significa; non puoi avere una libreria che lo faccia automaticamente per te.

  • Questo è , quindi vincerà il codice più breve in byte!


In realtà dovrebbe essere un terminale? O semplicemente un visualizzatore di testo colorato? Dovrebbe eseguire comandi?
Nathan Merrill,

Sto trovando difficile testarlo. Tutto ciò che invio a STDOUT utilizzando la sintassi specificata viene fornito in chiaro. Il mio profilo bash usa un prompt colorato, quindi rubato da quello che ho provato \n\[\e[32m\]\w\n\[\e[0m\]> (nome di directory verde, prompt semplice sulla riga successiva), ma non riesco a farlo funzionare da un programma (provato python e Java finora). Qualche idea?
Geobits il

@Geobits Try echo -e "\e[31mtest\e[0m".
Maniglia della porta

4
Penso che ti piacerebbe lolcat.
Anko,

1
Credo che per yoului figurato mezzi your program(al contrario di una chiamata a una funzione di libreria), e se ne assume determinenel senso di figure out, non come in choose. Cioè, è il tuo programma che dovrebbe gestire la mappatura: String ("red") | -> Intero (31). redè solo 31perché lo afferma, che le informazioni devono essere integrate nel programma. Sebbene si possa argomentare esattamente cosa significherebbe your program- possiamo usare le funzioni di manipolazione delle stringhe per scopi generici? - non imbrogliare / abusare palesemente.
Blutorange,

Risposte:


6

Rubino, 205 189 188 186 185 182 174 170 165 161 159 154 byte

Inserire lunghe stringhe di nomi di colori nel codice non sembra abbastanza nerd.

Fino a 170 in parte grazie a rubik. Ora le barre di scorrimento sono sparite!

Un miglioramento evidente e uno non così evidente, grazie alla risposta flessibile, senza il miglioramento ad esso, non avrei rivisitato questo!

Non più, ho salvato 4 byte con #sum. Non intendevo, ma ho appena notato che questa soluzione non distingue tra maiuscole e minuscole. Elabora felicemente {{RED|Red text}}.

Discarica esadecimale:

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

Puoi convertirlo con xxd -r hex.dump.

Il programma con tutti i caratteri non stampabili è sfuggito a scopo di riferimento:

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

Questa è una riga. Usalo in questo modo

ruby colors.rb -W0 < input.txt

La -W0bandiera elimina gli avvisi che verrebbero inviati stderraltrimenti. Tuttavia, il programma funziona bene senza alcun flag.

Produzione:

produzione


1
Ah, avevo la stessa idea, ma mi hai battuto! Penso che si potrebbe risparmiare un char con base 35, modulo 98 e XOR 1. La stringa sarebbe: '1?IYU_N[(\x0c\x16&",\x1f\x01'. La mia stringa è lunga 16 però. Vedo che il tuo ha 18 anni, quindi probabilmente dovrai adattarti.
rubik,

Grazie. I due byte aggiuntivi sono lì per supportare il codice colore 39/49, che imposta il colore back / forground predefinito. Ma grazie per il suggerimento, sono attualmente al lavoro e ci penserò ancora quando torno a casa.
Blutorange,

1
Bene, ho osservato che le uniche basi che puoi usare sono 35 e 36 (almeno la int()funzione di Python non può andare oltre 36). Quindi ho provato tutte le combinazioni per il modulo (da 2 a 10000, ma in teoria si potrebbe allargare la ricerca a tutto Unicode) e per lo xor, che ho mantenuto piccolo (da 1 a 9). Quindi ho considerato risultati accettabili solo quelli che non contenevano caratteri duplicati.
rubik,

Sì, è più o meno quello che ho fatto anch'io. Inizialmente, mi limitavo ai personaggi stampabili, perché questo ti dà meno mal di testa e sembra più bello. Ma dal momento che sto usando il byte 0x1e invece della sequenza di escape già, potrei anche usare più caratteri non stampabili. Per ottenere personaggi stampabili, ho usato x.to_i(base)%mod+offset. Ho quindi sostituito il +con ^, perché bene, sembra più bello. A parte questo, è inutile. Eliminazione ^99e modifica <<in +salvati per più byte. Grazie per la punta, non avrei notato diversamente!
Blutorange,

4

Rubino, 329 byte.

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

Di quale versione di Ruby ho bisogno per eseguire questo? Ho usato ruby 2.1.2p95e butto errore: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray,

Ciao @Ray, funziona in 2.0.0-p451. Non l'ho provato in 2.1.2. Qui funziona come una sceneggiatura e qui funziona in irb .
Alex Deva,

Funziona quando si inserisce il testo manualmente. In tal caso ruby colors.rb < input.txt, continuerà a funzionare in loop dopo che tutti gli input sono stati letti. Quindi getsrestituisce nil, che non possiede un #gsubmetodo, generando così un errore. Usa $><<$<.readinvece di loop{puts gets, è anche più breve; )
Blutorange,

Ho appena testato questa sceneggiatura con la faccina (vedi la domanda e l'immagine dal mio post), e non c'è un bordo giallo intorno alla faccina?
Blutorange,

4

Flex (lexer) - 226 197 192 182 168 (o 166)

Per farlo scendere a 166, cambia il \33personaggio in un vero personaggio di 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);

Compila ed esegui:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input

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

1

Cobra - 496

Potrebbe essere quasi una singola dichiarazione stampata.

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

Python, 561

Legge il testo da formattare da 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
È troppo prolisso per avere is not Noneun codegolf. Puoi usare !=None, per esempio.
Ray,

Inoltre, in def p(f,b,t), il tuo codice genererà a ZeroDivisionError. Qualsiasi cosa mod 0 è impossibile.
Decadimento beta

@BetaDecay che non è un numero intero in fase di modulo, è una stringa in fase di formattazione.
Sammitch,

Ricevo errori di sintassi non validi durante l' re.subesecuzione di questo
ArtOfCode

(commento in ritardo) Funziona questo codice a 499 byte ?
Erik the Outgolfer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.