こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

一定のスペースを空けて端を揃えて表示

一定のスペースを空けて端を揃えて表示

お世話になります。
一定のスペースを空けて文字を表示したとき、縦に綺麗に揃えて表示したいのですがやり方がわかりません。
例えば、

apple ここに15個分のスペース (2,8) (3,6)
orange ここに15個分のスペース (3,7) (9,8) (2,10)
dog ここに15個分のスペース (3,0)
fortunately ここに15個分のスペース (6,6)

このように、各行の左側には英単語1つ、そして15個分のスペースを空けて、右側にその単語の座標を表示します。
この時に、座標を縦にきれいに揃えて表示したいのですが、英単語の長さによってバラバラになってしまいます。
どのようにスペースをあけて表示すればよいのでしょうか?宜しくお願いします。

投稿日時 - 2010-04-30 04:08:05

QNo.5861140

すぐに回答ほしいです

質問者が選んだベストアンサー

5分遅れで同じ回答をしてしまった(^^;
ついでなので、もう少し文字種の範囲を広げても大丈夫なものを作成してみた。

public static void main(String[] args) {
String[] word = {"りんご", "おranじ", "犬", "fortunately"};
String[] coord = {"(2,8) (3,6)", "(3,7) (9,8) (2,10)", "(3,0)", "(6,6)"};
java.nio.charset.Charset charset = java.nio.charset.Charset.forName("Shift_JIS");
int width = word[0].getBytes(charset).length + 15;
for (int i = 0; i < word.length; i++) {
String format = "%-" + (width - word[i].getBytes(charset).length + word[i].length()) + "s%s%n";
System.out.printf(format, word[i], coord[i]);
}
}

前提として、
与えられた文字がシフトJISで表せるようなもので、
シフトJISで1バイトコードになるものがいわゆる半角(1桁幅)、
2バイトコードになるものがいわゆる全角(2桁幅)となるのなら、
上のようにすることで対処できる。

要点は文字数でなく文字を構成するコードが何バイトかを数えて、
2バイトなら2桁分のスペースを用意する。
これには、getBytesでStringからバイト配列を得てlengthでバイト数を得る。

今度は書式文字列は各行ごとに変わる可能性がある。
widthはword[0]の文字列幅に15スペース分を加えたもの。
"apple"でなく"りんご"なので21になる。
つまり座標の表示は22桁目からということになる。

各行の書式文字列での、
(width - word[i].getBytes(charset).length + word[i].length())
で、バイト数と文字数との差を求めて表示幅から引くことで、
1文字が2桁になる場合に対処している。

書式は使いどころによって便利なもので、
printfで書式出力するところを、
StringクラスのformatメソッドでStringインスタンスにすることもできたりする。

投稿日時 - 2010-04-30 15:13:45

お礼

皆さま本当にありがとうございました!
printf、非常に勉強になりました! Javaにこういうのがあったんですね^^すごく参考になりました!

投稿日時 - 2010-05-01 16:05:01

このQ&Aは役に立ちましたか?

11人が「このQ&Aが役に立った」と投票しています

回答(7)

ANo.6

#1です

 プログラミングの学習等で固定ピッチだという前提があれば、スペースでの位置合わせというのは有効ですが、現実にアプリ等を作っていく上では通用しないことがあるということです。
 また、実用的なアプリの多くはGUI環境で作られますから、コンソールに文字を表示する感覚とは違ってきます。GUIの画面上で文字を表示するならAWT等を使って、

  g.drawString("文字列", x, y);

みたいなやり方で座標指定して文字を表示します。
 こういう方法を使えば、厳密に位置合わせができるというわけです。(表示の開始位置だけだけど)

 英単語の開始位置をx1、座標の開始位置をx2で揃え、縦の位置yを1行の幅ずつ増やしていけばきちっと揃った状態で表示できるようになるわけです。

投稿日時 - 2010-04-30 15:06:52

ANo.5

エクセル使えば早くない?

投稿日時 - 2010-04-30 14:39:07

ANo.4

固定ピッチ端末で使用することは大前提であるとして、
シンプルにやるのならC言語でおなじみの書式付き出力を利用する方法がある。

public static void main(String[] args) {
String[] word = {"apple", "orange", "dog", "fortunately"};
String[] coord = {"(2,8) (3,6)", "(3,7) (9,8) (2,10)", "(3,0)", "(6,6)"};
String format = "%-" + (word[0].length() + 15) + "s%s%n";
for (int i = 0; i < word.length; i++) System.out.printf(format, word[i], coord[i]);
}

printfメソッドが書式による出力を行うメソッドであり、
formatがその書式を定める文字列になる。
formatは上のサンプルであれば "%-20s%s%n" という文字列になる。
前半部の"%-20s"はprintfメソッドの書式文字列を除いた最初の引数、つまりword[i]に対する書式、
次の"%s"はその次の引数coord[i]に対する書式を表す。
最後の"%n"は改行を表す。
"%s"というのは丁度必要な幅を確保した文字列という意味であり、
"%20s"のようにすると20桁分の幅を確保し、その中で文字列は右寄せという意味になる。
"%-20s"のように"-"をつけることで左寄せの意味になる。
つまり、"%-20s%s%n"をprintfメソッドに与えることは、
20桁分の出力欄を確保してその欄の中で左寄せでword[i]を出力し、
その次の桁、つまり21桁目からcoord[i]を出力し、
最後に改行を出力することの意となる。

この書式文字列"%-20s%s%n"をプログラム自身が動的に作っているのが、
"%-" + (word[0].length() + 15) + "s%s%n"
の部分。

> 最初の単語(apple)で15個のスペースを置き座標を表示するので、以下の単語はそれにあわせて表示する

とのことなので、
(word[0].length() + 15)
はword配列の最初の要素"apple"の文字数を数え、
さらにスペース分の15を加えた20という値を計算し、
その前後に残りの書式文字列のパーツを足して、書式文字列としている。

ただし、上のサンプルでは解決の難しい問題、unicode文字の表示幅判定の問題を抱えている。
例えば、word[i]が英単語だけならいいが、どれかを漢字などのいわゆる全角文字にすると表示が崩れる。
文字種を限っていけば簡単な判定の方法があるがunicode全般での判定は難しい。
word[i]を普通の英単語に限るなら判定しなくて済むので一番簡単になる。
これは質問者の問題領域次第なので、とりあえず一番簡単でいいもの前提にした。
もう一つ、サンプルでは補助文字に対応していないが、
こちらも質問者の問題領域次第なのであまり気にしなくていいかもしれない。
文字数数えを
(word[0].codePointCount(0, word[0].length()) + 15)
にすれば補助文字に対応するが、文字幅判定の方が実用上は大きい問題なのであまり意味がない気がする。

printfメソッドの書式の仕様についてはjava.util.Formatterクラスの文書に詳細がある。
C言語のprintf関数について検索してみても参考になると思う。
特にサンプルは文字列前提だったが数値を出力したい場合などは自分で調べてほしい。

また、たとえば、座標を複数個の数値などを要素とする配列やコレクションで持っている時に、
一行に複数の座標を出力する場合は、書式付きでword[i]だけを先に出力して、
さらに座標を個数分出力した後、改行するなどすればいいと思う。

投稿日時 - 2010-04-30 14:12:53

ANo.3

すいません思い出しました。
printfをつかって簡単にできました。
main()のループの中身を↓に変えると簡単にできます。
System.out.printf("%-20s%s\n",words[i],coo[i]);

投稿日時 - 2010-04-30 14:07:30

ANo.2

もっと簡単な方法があった気もしますが、ぱっと思いついたのでとりあえず。

public static void main(String[] args){

String[] words = {"apple","orange","dog"};
String[] coo = {"(2,8) (3,6)","(3,7) (9,8) (2,10)","(3,0)"};

for(int i = 0; i < words.length;i++){

System.out.print( words[i] );
printSpace(words[i]);
System.out.println( coo[i] );
}
}

public static void printSpace(String word){

String space = " ";
for(int i = 0; i < 15 - word.length(); i++){
System.out.print(space);
}
}

こんな感じに英単語の長さにあわせて毎回ループでスペースを表示させれば上手くいく
と思います。
まぁもっといい方法があると思うので他の方のでいい方法があればそちらでお願いします^^;

投稿日時 - 2010-04-30 10:56:02

ANo.1

 どういう環境で動作するものなのかによって違ってくるので一概には言えませんが……

 とりあえず、一律に15個のスペースじゃ位置が揃わないのは理解されてますよね?

 MS-DOSマシンのような完全なフォントピッチ固定の環境ならスペースを調整することで位置を揃えることは出来ますが、昨今のPC環境はそんな単純なものではないので、たとえ固定ピッチのフォントを使ったとしてもスペースの幅が文字幅と違ったりするので、この方法は良いとは言えないでしょう。

 各行を行単位で一括に処理するのではなく、英単語の項目と座標の項目は分け、それぞれ独自に座標を指定して表示するのが適切な方法だと思われます。

投稿日時 - 2010-04-30 04:30:07

補足

すみません、間違えました。すべての場合に15個分のスペースでは揃うわけないですよね・・・。
最初の単語(apple)で15個のスペースを置き座標を表示するので、以下の単語はそれにあわせて表示する、でした。

magicalpassさんの言うように、単語と座標をわけて表示するというのは、どのように書けばいいのでしょうか?

初めに英単語の表示で、
System.out.print("apple");
としたあとで
System.out.print("(2,8)");
System.out.print("(3,6)");
というように別けるということでしょうか?これだと単語の後すぐに座標が来てしまいやはり同じ結果になってしまいます。
すみません。どのように独自に指定して表示すればよいでしょうか?

投稿日時 - 2010-04-30 05:17:34

あなたにオススメの質問