Bisakah Anda membuat terminal saya kurang membosankan?

11

Terminal sangat membosankan akhir-akhir ini. Mereka dulu terlihat seperti ini:

Terminal 1 Terminal 2

Sekarang mereka hanya hambar dan kusam dan hitam-putih. Saya ingin Anda menulis saya sebuah program yang akan membuat terminal saya semua berwarna lagi!

Deskripsi

Ambil contoh ini kode Ruby:

Kode contoh

Sebagian besar terminal Linux mendukung urutan pelarian ini ( \esingkatan dari karakter pelarian), dan Windows dapat mendukungnya dengan ANSICON . Berikut adalah sintaks dari urutan escape spesifik yang dapat mengubah teks atau warna latar belakang string:

\e[{{COLOR}}m

di mana \esingkatan karakter pelarian ( 0x1Bdalam ASCII) dan {{COLOR}}diganti dengan jumlah warna yang ingin Anda gunakan (detail lebih lanjut tentang itu nanti). Teks yang muncul setelah urutan pelarian ini akan diformat seperti yang diarahkan, dan nilai 0akan mengatur ulang semua pemformatan.

Tantangan Anda adalah mengambil string yang menentukan beberapa teks yang mungkin mengandung warna, dan menampilkan versi warna-warni.

Input output

Teks normal berfungsi seperti biasa, dan dicetak secara harfiah. Misalnya, input wafflesmenghasilkan output yang sama, tanpa warna khusus.

Sintaksis untuk menentukan warna mirip dengan sintaksis Wikipedia . Misalnya, untuk mewarnai kata "warna merah" dengan warna merah dalam kalimat This is the color red!, inputnya adalah:

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

Warna latar juga berfungsi. Jika Anda ingin huruf hitam dengan latar belakang putih, Anda akan menggunakan ini:

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

Untuk hanya mendapatkan warna latar belakang, abaikan latar depan:

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

Spesifikasi

Dua kurung keriting terbuka selalu menentukan awal dari arahan warna . Dua kurung keriting penutup menentukan akhir. Kurung akan selalu cocok; tidak akan pernah ada {{tanpa yang sesuai }}, dan }}tidak akan pernah datang sebelum yang sesuai {{. Ini arahan warna tidak akan bersarang, dan {{tidak akan pernah muncul dalam direktif warna.

Dalam arahan warna, akan selalu ada satu atau dua |simbol. Jika ada satu, teks sebelum itu adalah warna foreground dan teks sesudahnya adalah string untuk ditampilkan dalam warna itu. Jika ada dua, teks sebelum yang pertama adalah warna latar depan, teks setelah yang pertama tetapi sebelum yang kedua adalah warna latar belakang, dan teks setelah yang kedua adalah string untuk ditampilkan. Bilah vertikal ini mungkin ada di luar arahan warna, dan harus dicetak secara harfiah.

Warna latar depan atau warna latar belakang (tetapi tidak keduanya) mungkin kosong, dalam hal ini Anda harus membiarkannya sebagai default. String terakhir (yang akan di-output) tidak akan pernah kosong.

Berikut adalah petunjuk untuk menampilkan teks dengan warna tertentu:

  • Sebuah urutan warna didefinisikan dalam bagian "Keterangan". Misalnya, urutan warna 42 akan menjadi "\e[42m".

  • Untuk mengatur warna, cetak urutan warna dari angka yang ditentukan di bawah ini:

     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
    
  • Nama warna peka huruf besar-kecil, dan nama warna yang tidak valid tidak akan pernah diberikan. Anda tidak harus menangani hal-hal seperti REDatau lightgrey(dieja dengan e).

  • Setelah Anda mencetak urutan warna, itu akan berlaku untuk semua teks yang mengikutinya. Untuk mengakhiri urutan warna (reset ke warna default), output urutan warna 0( "\e[0m").

Kasus cobaan

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

Ini akan menghasilkan wajah tersenyum ... dengan mata merah jahat.

Aturan

  • Anda tidak dapat menggunakan perpustakaan atau fungsi bahasa pemrograman Anda untuk secara otomatis mengurai warna. Ini berarti bahwa Anda harus menjadi orang yang menentukan apa "red"artinya; Anda tidak dapat memiliki perpustakaan secara otomatis untuk Anda.

  • Ini adalah , jadi kode terpendek dalam byte akan menang!

Gagang pintu
sumber
Seharusnya itu terminal? Atau hanya penampil teks berwarna-warni? Apakah ini seharusnya menjalankan perintah?
Nathan Merrill
Saya merasa sulit untuk menguji ini. Semua yang saya kirim ke STDOUT menggunakan sintaks yang ditentukan datang dalam teks biasa. Profil bash saya menggunakan prompt berwarna, jadi mencuri dari yang saya coba \n\[\e[32m\]\w\n\[\e[0m\]> (nama direktori hijau, prompt cepat di baris berikutnya), tapi saya tidak bisa membuatnya berfungsi dari sebuah program (mencoba python dan Java sejauh ini). Ada ide?
Geobits
@ Getobit Coba echo -e "\e[31mtest\e[0m".
Gagang Pintu
4
Saya pikir Anda akan menikmati lolcat.
Anko
1
Saya berpikir bahwa dengan youdia secara kiasan berarti your program(sebagai lawan dari panggilan ke fungsi perpustakaan), dan bahwa dia determinememahami arti figure out, bukan seperti dalam choose. Yaitu, program Anda yang harus menangani pemetaan: String ("red") | -> Integer (31). redhanya 31karena dia berkata begitu, bahwa informasi perlu diintegrasikan ke dalam program. Meskipun mungkin diperdebatkan dengan tepat apa yang akan dihitung your program- bisakah kita menggunakan fungsi manipulasi String tujuan umum? - jangan curang / menyalahgunakan.
blutorange

Jawaban:

6

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

Menempatkan string panjang nama warna dalam kode Anda tidak terlihat cukup kutu buku.

Turun ke 170 sebagian berkat rubik. Sekarang bilah gulir hilang!

Satu peningkatan yang jelas dan satu tidak begitu jelas, berkat jawaban yang fleksibel, tanpa peningkatan itu, saya tidak akan meninjau kembali ini!

Tidak lagi, saya menyimpan 4 byte dengan #sum. Saya tidak bermaksud, tapi saya perhatikan solusi ini juga tidak peka terhadap huruf besar-kecil. Itu dengan senang hati memproses {{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]]}

Anda dapat mengonversinya dengan xxd -r hex.dump.

Program dengan semua karakter yang tidak dapat dicetak keluar untuk tujuan referensi:

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

Itu satu baris. Gunakan seperti ini

ruby colors.rb -W0 < input.txt

The -W0bendera menekan peringatan yang akan dikirim ke stderrsebaliknya. Namun, program ini berfungsi dengan baik tanpa bendera.

Keluaran:

keluaran

blutorange
sumber
1
Ah, saya punya ide yang sama, tetapi Anda mengalahkan saya untuk itu! Saya pikir Anda bisa menghemat char dengan basis 35, modulus 98 dan XOR 1. String akan menjadi: '1?IYU_N[(\x0c\x16&",\x1f\x01'. Tali saya panjangnya 16. Saya melihat bahwa Anda berusia 18 tahun, jadi Anda mungkin harus menyesuaikan.
rubik
Terima kasih. Dua byte tambahan ada untuk mendukung kode warna 39/49, yang menetapkan warna back / forground default. Tapi terima kasih atas tipnya, saya saat ini sedang bekerja dan saya akan memikirkannya lagi ketika saya kembali ke rumah.
blutorange
1
Yah saya amati bahwa satu-satunya pangkalan yang dapat Anda gunakan adalah 35 dan 36 (setidaknya int()fungsi Python tidak bisa melampaui 36). Kemudian saya mencoba semua kombinasi untuk modulus (dari 2 hingga 10.000, tetapi secara teori kita dapat memperluas pencarian ke semua Unicode) dan untuk xor, yang saya pertahankan kecil (1 hingga 9). Lalu saya menganggap hasil yang dapat diterima hanya yang tidak mengandung karakter duplikat.
rubik
Ya, itu kurang lebih apa yang saya lakukan juga. Awalnya, saya membatasi diri pada karakter yang dapat dicetak, karena itu membuat Anda lebih sedikit sakit kepala dan terlihat lebih baik. Tapi karena saya sudah menggunakan byte 0x1e alih-alih urutan escape, saya mungkin juga menggunakan lebih banyak karakter yang tidak dapat dicetak. Untuk mencapai karakter yang dapat dicetak, saya menggunakan x.to_i(base)%mod+offset. Saya kemudian mengganti +dengan ^, karena, itu terlihat lebih keren. Selain itu, tidak perlu. Menjatuhkan ^99dan mengubah <<ke +disimpan untuk lebih banyak byte. Terima kasih atas tipnya, saya tidak akan memperhatikan sebaliknya!
blutorange
4

Ruby, 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"}}
Alex Deva
sumber
Apa versi Ruby yang saya perlukan untuk menjalankan ini? Saya menggunakan ruby 2.1.2p95dan membuang kesalahan: undefined method 'gsub' for nil:NilClass (NoMethodError) .
Ray
Hai @ Ray, ini berfungsi di 2.0.0-p451. Saya tidak mencobanya di 2.1.2. Ini berfungsi sebagai skrip dan Ini berfungsi di irb .
Alex Deva
Ini berfungsi saat Anda memasukkan teks secara manual. Jika Anda melakukannya ruby colors.rb < input.txt, itu akan tetap berulang setelah semua input telah dibaca. Lalu getskembali nil, yang tidak memiliki #gsubmetode, sehingga menimbulkan kesalahan. Gunakan $><<$<.readbukan loop{puts gets, itu juga lebih pendek; )
blutorange
Saya baru saja menguji skrip ini dengan wajah tersenyum (lihat pertanyaan dan gambar dari posting saya), dan tidak ada garis kuning di sekitar smiley?
blutorange
4

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

Untuk turun ke 166, ubah \33ke karakter pelarian aktual.

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

Kompilasi dan jalankan:

$ flex -o colour.c colour.l
$ gcc -o colour colour.c -lfl
$ ./colour < input
rici
sumber
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())
sinar
sumber
1

Cobra - 496

Ini bisa hampir menjadi pernyataan cetak tunggal.

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','')
Suram
sumber
1

Python, 561

Membaca teks ke format dari 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
sumber
2
Terlalu bertele-tele untuk memiliki is not Nonecodegolf. Anda dapat menggunakan !=None, misalnya.
Ray
Juga, dalam def p(f,b,t), kode Anda akan melempar a ZeroDivisionError. Apa pun mod 0 tidak mungkin.
Beta Decay
@ BetaDecay itu bukan bilangan bulat yang di-modulus, itu string yang diformat.
Sammitch
Saya mendapatkan kesalahan sintaks yang tidak valid saat re.submenjalankan ini
ArtOfCode
(komentar terlambat) Apakah kode 499 byte ini berfungsi?
Erik the Outgolfer