Terminalimi daha az sıkıcı yapabilir misin?


11

Terminaller bugünlerde çok sıkıcı . Eskiden şöyle görünürlerdi:

Terminal 1 Terminal 2

Şimdi sadece mülayim ve donuk ve siyah-beyazlar. Terminalimi yeniden renklendirecek bir program yazmanı istiyorum!

Açıklama

Şu örneği inceleyin: Ruby kodu:

Örnek kod

Çoğu Linux terminali bu kaçış dizilerini destekler ( \ekaçış karakterini temsil eder) ve Windows bunları ANSICON ile destekleyebilir . Bir dizenin metnini veya arka plan rengini değiştirebilen belirli kaçış dizisinin sözdizimi aşağıdadır:

\e[{{COLOR}}m

burada \e( 0x1BASCII'de) kaçış karakterini temsil eder ve {{COLOR}}yerine kullanmak istediğiniz rengin numarası gelir (bunun hakkında daha fazla ayrıntı). Bu çıkış dizisinden sonra gelen metin yönlendirildiği gibi biçimlendirilir ve değeri 0tüm biçimlendirmeyi sıfırlar.

Zorluğunuz, renk içerebilecek bazı metinleri belirten bir dize almak ve renkli bir sürümünü çıkarmaktır.

Giriş çıkış

Normal metin normal gibi çalışır ve tam olarak yazdırılır. Örneğin, girdi wafflesözel çıktı olmadan aynı çıktıyı verir.

Bir renk belirtme sözdizimi Wikipedia'nın sözdizimine benzer . Örneğin, cümledeki "kırmızı renk" kelimelerini kırmızı ile renklendirmek This is the color red!için giriş şu şekilde olur:

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

Arka plan renkleri de çalışır. Beyaz bir arka plan üzerinde siyah harfler istiyorsanız, bunu kullanırsınız:

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

Yalnızca bir arka plan rengi elde etmek için ön planı atlayın:

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

Şartname

İki açık kıvrık ayraç her zaman bir renk yönergesinin başlangıcını belirtir . Sonlanan iki kıvrık parantez ucu belirtir. Parantezler her zaman eşleşecektir; Orada bir asla {{karşılık gelen olmadan }}ve }}onun tekabül önce gelmeyecek {{. Bu renk yönergeleri iç içe {{geçmeyecek ve bir renk yönergesinde asla görünmeyecektir.

Bir renk yönergesinde her zaman bir veya iki |sembol olacaktır. Bir tane varsa, önceki metin ön plan rengidir ve sonraki metin bu renkte gösterilecek dizedir. İki tane varsa, birinciden önceki metin ön plan rengidir, birinciden sonraki ancak ikinciden önceki metin arka plan rengidir ve ikinciden sonraki metin görüntülenecek dizedir. Bu dikey çubuklar bir renk yönergesinin dışında bulunabilir ve tam olarak yazdırılmalıdır.

Ön plan rengi veya arka plan rengi (her ikisi birden değil) boş olabilir, bu durumda bunları varsayılan olarak bırakmalısınız. Son dize (çıktı alınacak olan) asla boş olmaz.

Belirli bir renkteki metnin çıktısı için talimatlar:

  • Bir renk dizisi "Açıklama" bölümünde tanımlanmıştır. Örneğin, 42'lik bir renk dizisi olacaktır "\e[42m".

  • Bir renk ayarlamak için, aşağıda belirtilen sayının renk sırasını yazdırın:

     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
    
  • Renk adları büyük / küçük harfe duyarlıdır ve asla geçersiz bir renk adı verilmez. Sen böyle şeyler işlemek gerekmez REDveya lightgrey(bir ile yazıldığından e).

  • Bir renk dizisini yazdırdıktan sonra, onu izleyen tüm metinler için geçerli olacaktır. Bir renk sırasını sona erdirmek için (varsayılan renge sıfırlama), 0( "\e[0m") renk sırasını girin .

Test durumu

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

Bu, gülen kırmızı yüzle gülen bir yüz çıkarmalıdır.

kurallar

  • Bir rengi otomatik olarak ayrıştırmak için programlama dilinizin kitaplıklarını veya işlevlerini kullanamazsınız. Bu, ne anlama geldiğini belirleyen kişi olmanız gerektiği "red"anlamına gelir; bunu sizin için otomatik olarak yapacak bir kütüphaneniz olamaz.

  • Bu , bu yüzden bayt içindeki en kısa kod kazanacak!


Aslında bir terminal olması gerekiyordu? Yoksa sadece renkli bir metin görüntüleyici mi? Komutları çalıştırması gerekiyor mu?
Nathan Merrill

Bunu test etmekte zorlanıyorum. Belirtilen sözdizimini kullanarak STDOUT'a gönderdiğim her şey düz metin olarak geliyor. Benim bash profil renkli bir istemi kullanır, bu yüzden denedim \n\[\e[32m\]\w\n\[\e[0m\]> (yeşil dizin adı, sonraki satırda düz istemi) çalmak , ama ben bir programdan çalışamaz (şimdiye kadar python ve Java çalıştı). Herhangi bir fikir?
Geobits

@Geobits Deneyin echo -e "\e[31mtest\e[0m".
Kapı Tokmağı

4
Bence zevk alırsın lolcat.
Anko

1
Bence youmecazi anlamda your program(bir kütüphane işlevine yapılan çağrının aksine) ve determineanlamında olduğu figure outgibi değil anlamına geldiğini düşünüyorum choose. Yani, eşlemeyi işlemesi gereken programınızdır: String ("red") | -> Integer (31). redbunun sadece 31bilginin programa entegre edilmesi gerektiğini söylemesidir. Tam olarak tartışılabilecek olmasına rağmen your program- genel amaçlı Dize düzenleme işlevlerini kullanabilir miyiz? - açıkça aldatma / kötüye kullanma.
blutorange

Yanıtlar:


6

Yakut, 205 189 188 186 185 182 174 170 165 161 159 154 bayt

Kodunuza uzun renk adı dizeleri koymak yeterince asosyal görünmüyor.

Kısmen 170'e kadar rubik. Şimdi kaydırma çubukları gitti!

Biri açık ve biri çok açık olmayan bir gelişme, esnek cevap sayesinde, iyileştirme olmadan, bunu tekrar gözden geçirmezdim!

Artık değil, #sum ile 4 bayt kurtardım. Niyet etmedim, ama bu çözümün de büyük / küçük harfe duyarlı olmadığını fark ettim. Mutlu bir şekilde işler {{RED|Red text}}.

Hex dökümü:

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

İle dönüştürebilirsiniz xxd -r hex.dump.

Yazdırılamayan tüm karakterleri içeren program referans amacıyla kaçmıştır:

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

Bu bir satır. Bu şekilde kullanın

ruby colors.rb -W0 < input.txt

-W0Bayrak gönderilecek uyarıları bastırır stderraksi. Ancak, program herhangi bir bayrak olmadan iyi çalışır.

Çıktı:

çıktı


1
Ah, aynı fikrim vardı, ama sen beni dövüyorsun! Ben baz 35, modül 98 ve xor 1 ile bir karakter kaydedebilirsiniz düşünüyorum '1?IYU_N[(\x0c\x16&",\x1f\x01'. Benim dize 16 uzunluğunda olsa. Seninkinin 18 olduğunu görüyorum, bu yüzden muhtemelen ayar yapmalısın.
rubik

Teşekkürler. İki ek bayt, varsayılan arka / yer rengini ayarlayan 39/49 renk kodunu desteklemek için vardır. Ama bahşiş için teşekkürler, şu anda işteyim ve eve döndüğümde biraz daha düşüneceğim.
blutorange

1
Kullanabileceğiniz tek üslerin 35 ve 36 olduğunu gözlemledim (en azından Python'un int()işlevi 36'yı geçemez). Sonra modül için tüm kombinasyonları denedim (2'den 10000'e kadar, ancak teoride , Unicode'un tümünü aramayı genişletebilir ) ve küçük tuttuğum xor için (1 ila 9). Sonra sadece yinelenen karakterler içermeyen kabul edilebilir sonuçları düşündüm.
rubik

Evet, az çok yaptığım da bu. Başlangıçta kendimi yazdırılabilir karakterlerle sınırlandırıyordum, çünkü bu size daha az baş ağrısı veriyor ve daha hoş görünüyor. Ama zaten kaçış dizisi yerine bayt 0x1e kullandığım için, daha fazla yazdırılamayan karakterler de kullanabilirim. Yazdırılabilir karakterler elde etmek için kullandım x.to_i(base)%mod+offset. Sonra yerini +ile ^iyi, soğutucuyu görünüyor, çünkü. Bunun dışında gereksizdir. Damlama ^99ve değişen <<için +daha bayt için kaydedilir. Bahşiş için teşekkürler, aksi takdirde fark olmaz!
blutorange

4

Ruby, 329 bayt.

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

Bunu çalıştırmak için hangi Ruby sürümüne ihtiyacım var? Kullandığım ruby 2.1.2p95ve hata atmak: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray

Merhaba @Ray, 2.0.0-p451'de çalışır. 2.1.2'de denemedim. Burada bir senaryo olarak çalışır ve Burada irb'de çalışır .
Alex Deva

Manuel olarak metin girdiğinizde çalışır. Bunu yaparsanız ruby colors.rb < input.txt, tüm giriş okunduktan sonra döngü devam edecektir. Sonra bir yönteme sahip olmayan getsdöndürür nil, #gsubböylece bir hata oluşturur. $><<$<.readBunun yerine kullanın loop{puts gets, aynı zamanda daha kısadır; )
blutorange

Bu senaryoyu gülen yüzle test ettim (soruya ve yazımdaki resme bakın) ve gülen yüzün etrafında sarı bir sınır yok mu?
blutorange

4

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

Bunu 166'ya düşürmek için, \33gerçek bir kaçış karakterine değiştirin.

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

Derleyin ve çalıştırın:

$ 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

Kobra - 496

Bu olabilir neredeyse tek baskı deyimi olun.

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

Stdin'den biçimlendirilecek metni okur.

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 NoneBir koda sahip olmak için çok ayrıntılı . !=NoneÖrneğin kullanabilirsiniz .
Ray

Ayrıca, def p(f,b,t)kodunuz a atar ZeroDivisionError. Mod 0 olan herhangi bir şey mümkün değildir.
Beta Çürümesi

@BetaDecay modüllü bir tam sayı değil, biçimlendirilmiş bir dize.
Sammitch

Bunu re.subçalıştırırken geçersiz sözdizimi hataları alıyorum
ArtOfCode

(geç yorum) Bu 499 baytlık kod çalışıyor mu?
Outgolfer Erik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.