エスケープシーケンスコンソール(CLI)サーバーサイドローカル環境同期・非同期

【Node.js】 コンソール(CLI)出力に色や装飾をつける方法

更新日:2021/06/07

Node.jsの実行結果をコンソールに出力するとき単純に文字を表示するのではなく、色を付けるなどするとメリハリがでてそれなりに見た目がよくなります。
そこで今回は、Node.jsの出力結果に色や装飾をおこなう方法をお伝えします。

 

単純な色指定をおこなう制御文字

コンソール出力した文字に色をつけるには制御文字という特殊な文字を使用します。

単純な色つけをおこなう制御文字を一覧にしてみます。

なお、端末によっては対応する色を変更できるものがあります。
変更してある場合は下記のようにならず、変更した色が表示されます。

出力イメージ制御文字
\x1b[30m
\x1b[31m
\x1b[32m
\x1b[33m
\x1b[34m
マゼンタマゼンタ\x1b[35m
シアンシアン\x1b[36m
\x1b[37m
文字色を
デフォルトに戻す
-\x1b[39m
リセット-\x1b[0m

リセットは、文字色だけではなく他の文字制御もリセットします。

使用する端末によって出力される色のRGB値がことなります。

ほぼ全ての端末で「これ〇色なの?」と疑問に感じる色だったりします。
白と言いながら灰色で表示される、などですね。

制御文字の後に入力した文字が、対応する色で出力されます。

使用例


console.log( "\x1b[31mこんにちは" );
console.log( "けーちゃんです");
console.log( "\x1b[0mよろしくね!");

コンソールへの出力結果は次のようになります。

コンソールへの出力結果:こんにちは(赤) けーちゃんです(赤) よろしくね!(白)

リセットするまで、制御文字が有効になっているのがわかりますね。

■\x1bはエスケープシーケンス

ASCIIコード表を見てください。
16進数で1bの位置に、ESCと書いてあります。
そのため、\x1bと後に続く [ 以降をまとめてエスケープシーケンスと呼んでいました。
現在では\nなどの画面上に表示できない特殊な文字もエスケープシーケンスと呼ばれています。

なお\xは後に続く2桁の16進数を、文字コードとして解釈する文字リテラルです。
例えば"\x0a"は10という値として解釈され、改行を表します。
さらに言えば、"\n"と同等です。

また\uという表記方法もあります。
これは4桁の16進数を続けることで、ユニコードを表します。

JavaScriptの文字列は内部的にはUTF-16のため、\xと\uのどちらを使用しても結果は同じになります。

制御文字は次のように変数から組み立てることもできます。

制御文字を変数から組み立てる


for( let i = 30 ; i <= 37 ; i ++ )
    console.log( `\x1b[${ i  }m${ i }`);

``は、テンプレートリテラルです。
テンプレートリテラルについては次のページを参考にしてください。
【JavaScript】 便利!テンプレートリテラルとは!だが普及しなそう…

次のように出力されます。

制御文字を変数から組み立てる

最初の行は見えていませんが、黒で30と表示されています。

console.logで出力すると、最後に改行されます。

ただ問題なのが、

改行して欲しくないときは、process.stdout.writeを使用します。

最後に改行させない


for( let i = 0 ; i <= 7 ; i ++ ) {
    process.stdout.write( `\x1b[${ i + 30 }m${  i + 30  }`);
    if( i % 4 === 3 ) process.stdout.write("\n");
}

上のコードは4回出力する毎に、一回改行しています。
改行したいときは、"\n"を出力します。

最後に改行させない

 

単純な背景色指定をおこなう制御文字

制御文字は背景色の指定もできます。

こちらも、端末によっては対応する色を変更できるものがあります。
変更してある場合は下記のようにならず、変更した色が表示されます。

背景色出力イメージ制御文字
\x1b[40m
\x1b[41m
\x1b[42m
\x1b[43m
\x1b[44m
マゼンタマゼンタ\x1b[45m
シアンシアン\x1b[46m
\x1b[47m
背景色を
デフォルトに戻す
-\x1b[49m

背景色変更の制御文字を使って、簡単なコードを作成してみます。

背景色の指定例


for( let i = 0 ; i <= 7 ; i ++ ){
    process.stdout.write( `\x1b[${ i + 40 }m`); // 背景色指定
    process.stdout.write( `\x1b[${ 37 - i }m`); // 文字色指定
    process.stdout.write( `${ i + 40 }`);
    if( i % 4 === 3 ) process.stdout.write("\n");
}

上のコードはわかりやすいように出力を分割していますが、次のようにまとめることができます。

process.stdout.write( `\x1b[${ i + 40 }m\x1b[${ 37 - i }m${ i + 40 }`);

実行すると、次のようになります。

背景色の指定結果

最後のリセットしていなかったため、次のコマンド入力の文字色と背景がおかしくなってしまいました。

文字に関する制御文字を使用したら、最後に必ず次のコードを実行して変更をリセットしておきましょう。

process.stdout.write( "\x1b[0m");

 

その他の文字に関する制御文字

色変更以外にも文字の装飾を変更する特殊文字があります。

効果出力イメージ制御文字
太字太字\x1b[1m
薄字(注)薄字\x1b[2m
イタリック表示italic\x1b[3m
アンダーラインアンダーライン\x1b[4m
ブリンク
1分あたり150回未満
ブリンク\x1b[5m
ブリンク(高速)
1分あたり150回以上
ブリンク\x1b[6m
前景・背景の色反転通常
反転
\x1b[7m
隠して表示。(透明で表示)隠して表示\x1b[37m
取り消し線取り消し線\x1b[0m

これらの出力結果は、WindowsのコマンドプロンプトやMacのターミナルなど、Node.jsを実行した端末によって異なります。

Node.jsは制御文字を含む文字データを標準出力などを経由して端末に受け渡しているだけです。
制御文字の解釈は端末でおこなうため、端末が対応しているかが重要となります。
Windowsのコマンドプロンプトはほとんど対応していません。

そのため、端末を制限せずに汎用的な運用をおこなう場合は、これらの制御文字を使用しないほうがいいです。

 

RGB・カラーコードでの色指定

ここまでの色指定は0から7までの8色でした。
制御文字はもっと多くの色を取り扱うことができます。

ただし、使用する端末が指定した色出力に対応していることが前提となります。

対象指定値制御文字
文字色RGB\x1b[38;2;R;G;Bm
カラーインデックス\x1b[38;5;カラーコードm
背景色RGB\x1b[48;2;R;G;Bm
カラーインデックス\x1b[48;5;カラーコードm

RGBでの色指定

R/G/Bは、それぞれ0から255の範囲で指定します。

簡単なコードで色の変化を確認してみます。

背景色をRGBで指定


process.stdout.write( `R/G `);
for( let r = 0 ; r <= 255 ; r += 10 ){
    process.stdout.write( (Math.floor(r ).toString().padStart(3,"0") + " " ));
}
process.stdout.write("\x0a");

for( let r = 0 ; r <= 255 ; r += 10 ){
    process.stdout.write((Math.floor(r ).toString().padStart(3,"0") + " " ));
    for( let g = 0 ; g <= 255 ; g += 10 ){

        process.stdout.write( `\x1b[48;2;${ r };${ g };255m`); 
        process.stdout.write( `   \x1b[0m `);
    }
    process.stdout.write("\x0a");
}

赤(R)と緑(G)を10単位で変化させています。
青(B)は255固定です。

文字色をRGB指定で変更する制御文字プログラムの結果

カラーインデックスでの色指定

カラーインデックスは、システムであらかじめ用意された256色を番号で指定する形式です。
単純な色指定をおこなう制御文字で紹介した8色は、カラーインデックス0から7番に対応しています。

簡単なコードで色を確認してみます。

背景色をカラーインデックスで指定


process.stdout.write( `   `);
for( let i = 0 ; i <= 9 ; i ++ ){
    process.stdout.write( ` +${i}  `);
}
process.stdout.write("\x0a");

for( let i = 0 ; i <= 255 ; i ++ ){
    if( i % 10 === 0 ) {
        process.stdout.write( (Math.floor(i / 10).toString().padStart(2,"0") + " " ));
    }
    process.stdout.write( `\x1b[48;5;${ i }m`); 
    process.stdout.write( `    \x1b[0m `);

    if( i % 10 === 9 ) process.stdout.write("\x0a");
}

文字色をカラーインデックス指定で変更する制御文字プログラムの結果

 

色・背景・装飾をまとめておこなう

ここまで、文字色や背景色などの指定を個々に行ってきました。

実は ; でつなげることで、一度に指定することができます。

例1:文字色と背景色を指定する

\x1b[31;42m

文字色赤、背景緑で表示されます。

例2:文字色と背景色(RGB)を指定する

\x1b[31;48;2;0;0;255m

文字色赤、背景R:0 G:0 B:255で表示されます。

例3:文字色(カラーインデックス)と背景色(RGB)および太字を指定する

\x1b[1;38;5;9;48;2;100;100;100m

太字、文字色インデックス9、背景R:100 G:100 B:100で表示されます。

更新日:2021/06/07

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。