質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Q&A

解決済

2回答

3734閲覧

ターミナル(コンソール)でプログレスバーを表示するには?

TEA

総合スコア65

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

0グッド

0クリップ

投稿2017/02/07 02:32

node.js (v4.3) でコンソールにプログレスバー(処理の進捗状況)のような情報を表示させたいと考えています。ご質問ですが、長い文字列でも表示させることは可能でしょうか?

質問内容(やりたいこと)

長いメッセージも、進捗のメッセージが行送りされずに表示したい。

できたこと

下記のtask_shortMessageように、短いメッセージであれば一行内で文字列が更新されて表示させる事ができました。

できないこと

しかし画面サイズの狭いコンソールでは、task_longMessageのように長いメッセージを表示させた時にメッセージが一行内で更新されず、行送りされて次々に表示されてしまいます。

javascript

1 2var main = () => { 3 Promise.resolve({message: "進捗:" , count: 0 }) 4 .then(task_shortMessage) 5 .then(task_shortMessage) 6 .then(task_shortMessage) 7 .then(task_shortMessage) 8 .then(task_shortMessage) 9 .then(task_longMessage) 10 .then(task_longMessage) 11 .then(task_longMessage) 12 .then(task_longMessage) 13 .then(task_longMessage) 14} 15 16const LONG_MESSAGE = "LongCharacterLongCharacterLongCharacterLongCharacter"; 17 18var task_shortMessage = (result) => { 19 return new Promise( (resolve , reject) => { 20 setTimeout( () => { 21 process.stdout.write(result.message + ++result.count + "\r"); 22 resolve(result); 23 }, 1000); 24 }); 25} 26 27var task_longMessage = (result) => { 28 return new Promise( (resolve , reject) => { 29 setTimeout( () => { 30 process.stdout.write(result.message + ++result.count + LONG_MESSAGE + "\r"); 31 resolve(result); 32 }, 1000); 33 }); 34} 35 36main();

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

readline.moveCursorを利用すれば解決できそうです。

js

1const readline=require("readline"); 2 3function progress(par){ 4 const LONG_MESSAGE = "LongCharacterLongCharacterLongCharacterLongCharacterLongCharacterLongCharacterLongCharacterLongCharacter"; 5 6 const empty=" ".repeat(10); 7 var gauge=("=".repeat(par)+empty).slice(0,10); 8 process.stdout.write(`\r進捗:[${gauge}]:${LONG_MESSAGE}`); 9} 10 11const g=(function*(){ 12 for(let i=0;i<=10;i++){ 13 yield setTimeout(()=>g.next(),200); 14 progress(i); 15 readline.moveCursor(process.stdout,0,-1); 16 } 17})(); 18g.next();

投稿2017/02/09 04:01

編集2017/02/09 04:09
YOS_G-sepc

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEA

2017/02/09 06:16 編集

教えていただきありがとうございました!サンプルコードも分かりやすく大変参考になりました。 readline.moveCursor(process.stdout,0,-1);の「-1」は戻す行数を表している事が理解できました。 ユーザーの画面サイズによっては、メッセージが2行以上にわたって表示されるケースもあるかと思いますが、そういったケースでは「-1」の部分を「-2」などにに変更することになるかと思います。 メッセージの表示によって改行されてしまった行数を、何かの方法で取得する事は難しいでしょうか?
guest

0

ベストアンサー

その改行する目安なわけですが、コンソールには何桁目で必ず改行するという限界値が決められているので、それを各ユーザーから取得すれば行数は計算できると思います。
勿論、出力する値はこちらにあるわけなので、

floor(出力文字数(出力バイト数(幅))/行最大文字数)

で計算するといいのかなぁと考えました。

そして、肝心の行最大文字数の取得方法なんですが、これはNode.jsからの方法は分からなかったです。
代替案ですが、Node.jsは一応、コマンドプロンプトとかターミナルをchild_process.exec/execSyncから呼べますので、各環境に合わせてコマンドを叩けば取得できるのではないかと思います。

当方はWindows環境なので、Linux/Unixは分かりませんけど、Windowsではなんとか取得できたので、ソースを載せておきます。
色々弄って遊んでいたら少々プログラムが大きくなってしまいましたが、そこは目をつぶってください。

js

1const readline=require("readline"); 2const exec=require("child_process").execSync; 3const rl=readline.createInterface(process.stdin,process.stdout); 4 5class Progress{ 6 constructor(width,parMax){ 7 //最大の列数 8 this.columns=exec("mode") //コマンドプロンプトからmodeを呼び出して、 9 .toString() //文字列として取得して、 10 .split(/\r\n/) //改行で分割し、 11 .filter(val=>{ //文字化けした" 桁数: "(=" ����: ")を検索して、 12 if(val.replace(" ����: ","")!=val) return val; 13 })[0].replace(" ����: ","")|0 //無駄な文字を消して整数に変換。 14 15 //進捗度 16 this.par=0; 17 //目標進捗度 18 this.parMax=parMax; 19 //プログレスバーの長さ 20 this.width=width; 21 } 22 23 //プログレスバーの更新 24 view(message){ 25 const parcent=this.par/this.parMax; 26 const widthNow=Math.floor(this.width*parcent); 27 28 const gauge=(">".repeat(widthNow)+" ".repeat(this.width-widthNow)); 29 const output=`#[${gauge}]#(${(parcent*100).toFixed(1)}%<-${this.par}/${this.parMax})`; 30 31 //列数と文字数(半角のみ)から実際の行数を計算 32 const rows=Math.floor(message.length/this.columns)+2; 33 console.log(output); 34 35 //現在位置より下を消去する 36 readline.clearScreenDown(process.stdout); 37 38 console.log(message); 39 40 //行数分上に移動。 41 readline.moveCursor(process.stdout,0,-rows); 42 43 this.par++; 44 } 45 46 //プログレスバーの完了 47 done(lastMessage){ 48 //lastMessageの左を埋める文字数 49 const sideLen=Math.floor((this.width-lastMessage.length)/2); 50 51 var gauge="=".repeat(sideLen)+lastMessage 52 gauge+="=".repeat(this.width-gauge.length) 53 const output=`#[${gauge}]#(100%<-${this.parMax}/${this.parMax})`; 54 55 //最大列数に合うように空白埋めして表示 56 process.stdout.write(output+" ".repeat(this.columns-output.length)+"\r"); 57 58 //現在位置より下を消去する 59 readline.clearScreenDown(process.stdout); 60 } 61} 62 63const g=(function*(){ 64 const firstMsg="FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep FirstStep"; 65 const secondMsg="SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep SecondStep"; 66 const thirdMsg="ThirdStep ThirdStep ThirdStep ThirdStep"; 67 console.log("START!"); 68 69 const width=55; 70 const works=270; 71 const prg=new Progress(width,works); 72 73 for(let i=0;i<=works;i++){ 74 yield setTimeout(()=>g.next(),90); 75 if(i<40){ 76 prg.view(firstMsg); 77 } 78 else if(i<90){ 79 prg.view(secondMsg); 80 } 81 else{ 82 prg.view(thirdMsg); 83 } 84 } 85 prg.done(">> Done! <<"); 86 console.log("終了しました!"); 87 rl.once("line",process.exit); 88})(); 89g.next();

追記:

js

1> process.stdout 2WriteStream { 3 ..., 4 columns: 80, 5 rows: 25, 6 ..., 7 destroy: [Function] } 8 9> process.stdout.columns 1080

process.stdoutを叩いてみたらその中にcolumns入ってました。
これで置換すればどのプラットフォームでも桁数を取得できるのではないでしょうか。

投稿2017/02/09 13:00

編集2017/02/10 03:46
YOS_G-sepc

総合スコア29

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TEA

2017/02/10 08:55

貴重なお時間を割いて頂き、詳細に教えていだき本当にありがとうございました。目からウロコといいますか、とても勉強になるアプローチで参考になりました!columnsがあるのですね。 また後で教えていただいた方法を試してみたいと思いますが、まずはベストアンサーにさせていただきました。本当にありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問