Können Sie mein Terminal weniger langweilig machen?

11

Terminals sind heutzutage so langweilig . Früher sahen sie so aus:

Terminal 1 Terminal 2

Jetzt sind sie nur langweilig und langweilig und schwarz-weiß. Ich möchte, dass Sie mir ein Programm schreiben, das mein Terminal wieder bunt macht!

Beschreibung

Nehmen Sie dieses Beispiel Ruby-Code:

Beispielcode

Die meisten Linux-Terminals unterstützen diese Escape-Sequenzen ( \esteht für das Escape-Zeichen), und Windows kann sie mit ANSICON unterstützen . Hier ist die Syntax der spezifischen Escape-Sequenz, die den Text oder die Hintergrundfarbe einer Zeichenfolge ändern kann:

\e[{{COLOR}}m

Dabei \esteht das Escape-Zeichen ( 0x1Bin ASCII) und {{COLOR}}wird durch die Nummer der Farbe ersetzt, die Sie verwenden möchten (dazu später mehr Details). Text, der nach dieser Escape-Sequenz kommt, wird wie angegeben formatiert, und ein Wert von 0setzt alle Formatierungen zurück.

Ihre Herausforderung besteht darin, eine Zeichenfolge zu verwenden, die einen Text angibt, der möglicherweise Farbe enthält, und eine farbenfrohe Version davon auszugeben.

Input-Output

Normaler Text funktioniert genauso wie normal und wird buchstäblich gedruckt. Beispielsweise wafflesliefert die Eingabe dieselbe Ausgabe ohne spezielle Farbe.

Die Syntax zum Festlegen einer Farbe ähnelt der Wikipedia-Syntax . Um beispielsweise die Wörter "die Farbe Rot" im Satz in Rot zu färben This is the color red!, wäre die Eingabe:

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

Hintergrundfarben funktionieren auch. Wenn Sie schwarze Buchstaben auf weißem Hintergrund möchten, würden Sie Folgendes verwenden:

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

Lassen Sie den Vordergrund weg, um nur eine Hintergrundfarbe zu erhalten:

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

Spezifikation

Zwei offene geschweifte Klammern geben immer den Beginn einer Farbanweisung an . Zwei schließende geschweifte Klammern geben das Ende an. Die Klammern stimmen immer überein. es wird niemals ein {{ohne ein entsprechendes geben }}, und ein }}wird niemals vor seinem korrespondierenden kommen {{. Diese Farbanweisungen werden nicht verschachtelt, und a {{wird niemals in einer Farbanweisung angezeigt.

Innerhalb einer Farbanweisung gibt es immer entweder ein oder zwei |Symbole. Wenn es eine gibt, ist der Text davor die Vordergrundfarbe und der Text danach die Zeichenfolge, die in dieser Farbe angezeigt werden soll. Wenn es zwei gibt, ist der Text vor dem ersten die Vordergrundfarbe, der Text nach dem ersten, aber vor dem zweiten die Hintergrundfarbe und der Text nach dem zweiten die anzuzeigende Zeichenfolge. Diese vertikalen Balken können außerhalb einer Farbrichtlinie vorhanden sein und sollten wörtlich gedruckt werden.

Die Vordergrund- oder Hintergrundfarbe (aber nicht beide) ist möglicherweise leer. In diesem Fall sollten Sie sie als Standard beibehalten. Die letzte Zeichenfolge (die auszugebende) wird niemals leer sein.

Hier sind die Anweisungen zum Ausgeben von Text einer bestimmten Farbe:

  • Eine Farbsequenz wird im Abschnitt "Beschreibung" definiert. Zum Beispiel wäre eine Farbsequenz von 42 "\e[42m".

  • Um eine Farbe festzulegen, drucken Sie die Farbsequenz der unten angegebenen Nummer:

     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
    
  • Farbnamen unterscheiden zwischen Groß- und Kleinschreibung, und ein ungültiger Farbname wird niemals angegeben. Sie müssen nicht mit Dingen wie REDoder lightgrey(geschrieben mit einem e) umgehen .

  • Nachdem Sie eine Farbsequenz gedruckt haben, gilt sie für den gesamten darauf folgenden Text. Geben Sie eine Farbsequenz von 0( "\e[0m") aus , um eine Farbsequenz zu beenden (auf die Standardfarbe zurücksetzen ).

Testfall

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

Dies sollte ein Smiley-Gesicht ausgeben ... mit bösen roten Augen.

Regeln

  • Sie dürfen keine Bibliotheken oder Funktionen Ihrer Programmiersprache verwenden, um eine Farbe automatisch zu analysieren. Dies bedeutet, dass Sie derjenige sein müssen, der bestimmt, was "red"bedeutet; Eine Bibliothek kann das nicht automatisch für Sie erledigen.

  • Dies ist , also gewinnt der kürzeste Code in Bytes!

Türknauf
quelle
Es soll eigentlich ein Terminal sein? Oder nur ein bunter Textbetrachter? Soll es Befehle ausführen?
Nathan Merrill
Es fällt mir schwer, das zu testen. Alles, was ich mit der angegebenen Syntax an STDOUT sende, wird im Klartext geliefert. Mein Bash-Profil verwendet eine farbige Eingabeaufforderung, also habe ich versucht, sie zu stehlen \n\[\e[32m\]\w\n\[\e[0m\]> (grüner Verzeichnisname, einfache Eingabeaufforderung in der nächsten Zeile), aber ich kann sie nicht über ein Programm zum Laufen bringen (bisher Python und Java ausprobiert). Irgendwelche Ideen?
Geobits
@ Geobits versuchen echo -e "\e[31mtest\e[0m".
Türknauf
4
Ich denke du würdest es genießen lolcat.
Anko
1
Ich denke, dass youer damit im übertragenen Sinne meint your program(im Gegensatz zu einem Aufruf einer Bibliotheksfunktion) und dass er determineim Sinne von figure out, nicht wie in choose. Das heißt, es ist Ihr Programm, das die Zuordnung handhaben sollte: String ("rot") | -> Integer (31). redNur 31weil er es so sagt, müssen Informationen in das Programm integriert werden. Obwohl genau argumentiert werden kann, worauf es ankommt your program- können wir universelle String-Manipulationsfunktionen verwenden? - nicht offen betrügen / missbrauchen.
Blutorange

Antworten:

6

Ruby, 205 189 188 186 185 182 174 170 165 161 159 154 Bytes

Das Einfügen langer Farbnamenfolgen in Ihren Code sieht nicht nerdig genug aus.

Bis auf 170 teilweise dank rubik. Jetzt sind die Bildlaufleisten weg!

Eine offensichtliche und eine nicht so offensichtliche Verbesserung, dank der flexiblen Antwort, ohne die Verbesserung hätte ich dies nicht noch einmal wiederholt!

Nicht mehr, ich habe 4 Bytes mit #sum gespeichert. Ich hatte es nicht vor, aber ich habe gerade bemerkt, dass bei dieser Lösung auch die Groß- und Kleinschreibung nicht berücksichtigt wird. Es verarbeitet glücklich {{RED|Red text}}.

Hex Dump:

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

Sie können es mit konvertieren xxd -r hex.dump.

Das Programm mit allen nicht druckbaren Zeichen wurde zu Referenzzwecken maskiert:

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

Das ist eine Zeile. Verwenden Sie es so

ruby colors.rb -W0 < input.txt

Das -W0Flag unterdrückt Warnungen, an die stderrandernfalls gesendet werden würde . Das Programm funktioniert jedoch ohne Flags.

Ausgabe:

Ausgabe

blutorange
quelle
1
Ah, ich hatte die gleiche Idee, aber du hast mich geschlagen! Ich denke, Sie könnten ein Zeichen mit Basis 35, Modul 98 und x oder 1 speichern. Die Zeichenfolge wäre : '1?IYU_N[(\x0c\x16&",\x1f\x01'. Meine Saite ist allerdings 16 lang. Ich sehe, deine ist 18, also musst du dich wahrscheinlich anpassen.
Rubik
Vielen Dank. Die zwei zusätzlichen Bytes unterstützen den Farbcode 39/49, der die Standardfarbe für Hintergrund / Hintergrund festlegt. Aber danke für den Tipp, ich bin gerade auf der Arbeit und werde noch etwas darüber nachdenken, wenn ich wieder zu Hause bin.
Blutorange
1
Nun, ich habe festgestellt, dass die einzigen Basen, die Sie verwenden können, 35 und 36 sind (zumindest Pythons int()Funktion kann 36 nicht überschreiten). Dann habe ich versucht alle Kombinationen für den Modul (2-10000, aber in der Theorie könnte man die Suche erweitern alle von Unicode) und für die xor, die ich klein gehalten (1 bis 9). Dann betrachtete ich akzeptable Ergebnisse nur als solche, die keine doppelten Zeichen enthielten.
Rubik
Ja, das habe ich mehr oder weniger auch getan. Ursprünglich beschränkte ich mich auf druckbare Zeichen, da dies weniger Kopfschmerzen verursacht und besser aussieht. Da ich jedoch bereits das Byte 0x1e anstelle der Escape-Sequenz verwende, kann ich auch mehr nicht druckbare Zeichen verwenden. Um druckbare Zeichen zu erhalten, habe ich verwendet x.to_i(base)%mod+offset. Ich ersetzen dann die +mit ^, weil gut, es kühler aussieht. Davon abgesehen ist es nicht notwendig. Löschen des ^99und Ändern <<auf +gespeichert für mehr Bytes. Danke für den Tipp, sonst hätte ich es nicht bemerkt!
Blutorange
4

Ruby, 329 Bytes.

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
quelle
Welche Version von Ruby brauche ich, um dies auszuführen? Ich habe verwendet ruby 2.1.2p95und es wirft Fehler : undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray
Hallo @ Ray, es funktioniert in 2.0.0-p451. Ich habe es in 2.1.2 nicht versucht. Hier funktioniert es als Skript und hier funktioniert es in irb .
Alex Deva
Dies funktioniert, wenn Sie Text manuell eingeben. Wenn Sie dies tun ruby colors.rb < input.txt, wird die Schleife fortgesetzt, nachdem alle Eingaben gelesen wurden. Dann wird getszurückgegeben nil, das keine #gsubMethode besitzt, wodurch ein Fehler ausgelöst wird. Verwenden Sie $><<$<.readstatt loop{puts gets, es ist auch kürzer; )
Blutorange
Ich habe dieses Skript gerade mit dem Smiley-Gesicht getestet (siehe Frage und Bild aus meinem Beitrag), und es gibt keinen gelben Rand um den Smiley?
Blutorange
4

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

Um es auf 166 zu bringen, ändern Sie das \33in ein tatsächliches Escape-Zeichen.

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

Kompilieren und ausführen:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input
Rici
quelle
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())
Strahl
quelle
1

Cobra - 496

Es könnte fast eine einzelne Druckanweisung sein.

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
quelle
1

Python, 561

Liest den zu formatierenden Text von 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())
Sammitch
quelle
2
Es ist zu ausführlich, um es is not Nonein einem Codegolf zu haben . Sie können !=Nonezum Beispiel verwenden.
Ray
Außerdem wird def p(f,b,t)Ihr Code in a werfen ZeroDivisionError. Alles Mod 0 ist unmöglich.
Beta Decay
@BetaDecay, das ist keine Ganzzahl, die moduliert wird, sondern eine Zeichenfolge, die formatiert wird.
Sammitch
Ich re.sub
erhalte
(später Kommentar) Funktioniert dieser 499-Byte-Code ?
Erik der Outgolfer