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

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

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

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

855閲覧

formatでの空白表示

oimo0505

総合スコア22

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2022/09/12 10:52

編集2022/09/12 11:26

前提

 現在お小遣い帳を作成しており、入力した値をObject型の配列に格納し、名目を判別後各Wallet,FoodExpences,BookFee,DailyCost型(各クラスはスーパークラスItemのサブクラス)にキャストしたものを表に表示させようとしています。
(残額の行はまだ計算式を書いていないためずっと空白のままです。)
表はハイフンなどを用いて自作の枠組みを作っているのですが、表の枠を一定の大きさで保つために入力した値のByte数を判定するメソッドを用い、(表の枠の大きさ)ー(入力した値のByte数)を計算しformatを用いてその数だけ空白を値の右側に出力しようとしています。AddSort2クラスで作っている枠に最終的に合わせようと思っています。

 しかし、収入、支出の行がByte数を判定したものを出力した場合予想通りの値(例:全角で20000と入力されていれば10)が出力されたのですが、formatを用い表形式で出力しようとした際に、入力した値の桁数が違う場合に出力される空白の数が変わり表の枠(|部分)がガタガタになってしまいます。
formatに関して詳しく調べたつもりなのですがどうしてこのような問題が発生してしまうかわからなかったため質問させていただきました。説明が長くなってしまい申し訳ございません。よろしくお願いします。

csvファイルの内容

お財布 収 20000 N/A
食費    支 2000 N/A
書籍    支 1500 N/A
日用品費 支 500    N/A
お財布 収 5000 N/A
お財布 収 1    N/A
お財布 収 10000 N/A
食費    支 10000 N/A

追記:
表での表示はターミナル内で行いたいと考えています。

実現したいこと

(表の枠の大きさ)ー(入力した値のByte数)の差だけ空白を値の右側に出力

発生している問題・エラーメッセージ

空白の数の計算まではできているのだがその数だけの空白の出力ができていないため表の縦に分割する場所がガタガタになっている。

該当のソースコード

AddSort2.java

Java

1package bookmoney; 2 3 4public class AddSort2 { 5 private int balance = 0; 6 public void getTableParts(Object [] itemArray) { 7 8 String format = "|%1$-10s|%2$-12s|%3$-12s|%4$-4s|%5$-20s|\n"; 9 System.out.format(format, "名目", "収入", "支出", "残額", "補足"); 10 11 System.out.println("-------------+--------------+--------------+------+-----------------------"); 12 13 for (int i = 0; i < itemArray.length; i++) { 14 if (itemArray[i] instanceof Wallet) { 15 Wallet wallet = (Wallet)itemArray[i]; 16 System.out.println(wallet.getTableParts()); 17 System.out.println("-------------+--------------+--------------+------+-----------------------"); 18 } else if (itemArray[i] instanceof FoodExpences) { 19 FoodExpences foodExpences = (FoodExpences)itemArray[i]; 20 System.out.println(foodExpences.getTableParts()); 21 System.out.println("-------------+--------------+--------------+------+-----------------------"); 22 } else if (itemArray[i] instanceof BookFee) { 23 BookFee bookFee = (BookFee) itemArray[i]; 24 System.out.println(bookFee.getTableParts()); 25 System.out.println("-------------+--------------+--------------+------+-----------------------"); 26 } else if (itemArray[i] instanceof DailyCost) { 27 DailyCost dailyCost = (DailyCost) itemArray[i]; 28 System.out.println(dailyCost.getTableParts()); 29 System.out.println("-------------+--------------+--------------+------+-----------------------"); 30 } 31 } 32 } 33 }

Wallet.java  これと型の名前だけが違うクラスが各名目ごとにあります。

Java

1package bookmoney; 2 3import java.util.*; 4public class Wallet extends Item{ 5 private String wallet; 6 7 public Wallet (String name, String flag, String amount, String wallet) { 8 super(name, flag, amount); 9 this.name = getName(); 10 this.flag = getFlag(); 11 this.amount = getAmount(); 12 this.wallet = wallet; 13 } 14 15 public String getWallet() { 16 return this.wallet; 17 } 18 19 public String getTableParts() { 20 String lineTable = null; 21 HanZen2 han1Zen2 = new HanZen2(); 22 23 String name = this.name; 24 String flag = this.flag; 25 String amountStr = this.amount; 26 String note = this.wallet; 27 String amount = ""; 28 String in = ""; 29 String out = ""; 30 if (flag.equals("収")) { 31 in = amountStr; 32 } else if (flag.equals("支")) { 33 out = amountStr; 34 } 35 36 int nameBlank = 15 - han1Zen2.getHan1Zen2(name); 37 int inBlank = 14 - han1Zen2.getHan1Zen2(in); 38 int outBlank = 14 - han1Zen2.getHan1Zen2(out); 39 int noteBlank = 25- han1Zen2.getHan1Zen2(note); 40 // String inBlankStr = String.valueOf(inBlank); 41 42 String namelineTable = name.format(("|%-" + nameBlank + "s"), name); 43 String inlineTable = in.format(("|%-" + inBlank + "s" ), in); 44 String outlineTable = out.format(("|%-" + outBlank + "s" ), out); 45 String amountTable = amount.format(("|%-6s"), amount); 46 String notelineTable = note.format(("|%-" + noteBlank + "s|" ), note); 47 lineTable = namelineTable + inlineTable + outlineTable + amountTable + notelineTable; 48 // lineTable = String.valueOf(inBlank ); 49 50 51 return lineTable; 52 } 53 } 54 55

DataLoad2.java クラスを判定しキャストさせる

Java

1package bookmoney; 2 3import java.io.BufferedReader; 4import java.io.FileReader; 5import java.io.*; 6import java.nio.file.Files; 7import java.nio.file.Path; 8import java.nio.file.Paths; 9 10public class DataLoad2 { 11 private Object [] itemArray; 12 13 public Object[] dataLoadMethod() { 14 15 try (BufferedReader br = new BufferedReader(new FileReader("bookmoney/PocketMoney.csv"))) { 16 int count = 0; 17//ファイルの行数取得 18 Path file = Paths.get("bookmoney/PocketMoney.csv"); 19 long lineNum = Files.lines(file).count(); 20 int lineInt = Math.toIntExact(lineNum); 21 22 itemArray = new Object[lineInt]; 23 24 String s; 25 while ((s = br.readLine()) != null) { 26 // 読み込んだ行を、「,」で分割する 27 String data[] = s.split(","); 28 if (data[0].equals("お財布")) { 29 itemArray[count] = new Wallet(data[0], data[1], data[2], data[3]); 30 } else if (data[0].equals("食費")) { 31 itemArray[count] = new FoodExpences(data[0], data[1], data[2], data[3]); 32 } else if (data[0].equals("書籍")) { 33 itemArray[count] = new BookFee(data[0], data[1], data[2], data[3]); 34 } else if (data[0].equals("日用品費")) { 35 itemArray[count] = new DailyCost(data[0], data[1], data[2], data[3]); 36 } 37 count++; 38 } 39 } catch (IOException e) { 40 System.out.println("入出力エラーです"); 41 } 42 return itemArray; 43 } 44}

HanZen2.java 値のByte数取得

Java

1package bookmoney; 2 3public class HanZen2 { 4 public static int getHan1Zen2(String str) { 5 //戻り値 6 int ret = 0; 7 8 //全角半角判定 9 char [] c = str.toCharArray(); 10 for (int i = 0; i < c.length; i++) { 11 if (String.valueOf(c[i]).getBytes().length <= 1) { 12 ret += 1; //半角なら+1 13 } else { 14 ret += 2;//全角なら+2 15 } 16 } 17 return ret; 18 } 19} 20

Item.java

Java

1package bookmoney; 2 3public class Item { 4 protected String name; 5 protected String flag; 6 protected String amount; 7 8 public Item (String name, String flag, String amount) { 9 this.name = name; 10 this.flag = flag; 11 this.amount = amount; 12 } 13 //getter 14 public String getName() { 15 return this.name; 16 } 17 public String getFlag() { 18 return this.flag; 19 } 20 public String getAmount() { 21 return this.amount; 22 } 23}

実行するクラス(該当箇所を抜粋しています)

Java

1 case 1: 2 3 System.out.println("《データロード》"); 4 DataLoad2 data = new DataLoad2(); 5 itemArray = data.dataLoadMethod(); 6 System.out.println("データロードが完了しました。"); 7 8 break; 9 case 2: 10 11 System.out.println("《表表示》"); 12 AddSort2 addSort2 = new AddSort2(); 13 addSort2.getTableParts(itemArray); 14 15 break;

試したこと

空白の出力数を確認したが予想通りの値が出力された

補足情報(FW/ツールのバージョンなど)

IntelliJを使用しています。

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

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

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

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

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

m.ts10806

2022/09/12 10:57

CSVなら カンマ区切りでは。(もしくはタブ区切り) 空白であわせるというのは聞いたことがないです。
oimo0505

2022/09/12 11:18 編集

m.ts10806様 コメントありがとうございます。 説明で不足していたのですがcsvファイルに出力する際はカンマ区切りで出力するようにしています。 その後ターミナル内で自作の枠組みを作り表を表示させようと思っていて、splitでカンマごとに配列に格納しそれを表示させる際に次の配列を出力するまでの空白を表示させようと考えています。 例えば、少しずれていますがこんな感じです 名目    |収入   |支出    |補足 ------------------------------------------------------------- array[0] |array[1] |array[2] |array[3]
m.ts10806

2022/09/12 11:19

分かりやすいように追記してもらったらと。 ただ、ターミナルでレイアウト調整はかなり困難を極めると思います。 文字数だけでなく全角半角で違いますし、ターミナルのフォントとかでも容赦なくずれます。 GuiもしくはWebで画面表示した方が良いと思います。
dodox86

2022/09/12 11:21

> 空白であわせるというのは聞いたことがないです。 質問本文中の説明が長くて正直、私などは要旨を把握しかねているのですが、各項目の文字列を固定長にして、指定文字数に満たない部分は空白で埋めたいということでしょうかね。 そうであれば、一部の固定長レコードのフォーマットなどで存在することもありますね。
dodox86

2022/09/12 11:23

ああ、単にターミナル上での表示だけのお話なのですね。
oimo0505

2022/09/12 11:25

ご指摘ありがとうございます。質問の方に追記させていただきます。 半角全角の問題の方は判定メソッドを作成することで解決したと考えていたのですが、format作成の段階で計算した数値通りにならないため質問させていただきました。 フォントが原因の可能性があるのは初耳で気にもしていませんでした、、、。 ターミナル内での出力が要件になっているためどうしても解決しないといけないんですよね、、
dodox86

2022/09/12 11:29

あと、見た目の全角文字が2バイトとは限らないですよ。StringをgetBytes()するときの文字コードによります。シフトJISとUTF-8の違いを確認してみてください。
oimo0505

2022/09/12 11:30

dodox86様 コメントありがとうございます。 >各項目の文字列を固定長にして、指定文字数に満たない部分は空白で埋めたいということでしょうかね。 その通りです。語彙力がないせいで説明が長くなってしまい申し訳ございません。
Crimson_Tide

2022/09/12 13:40

https://teratail.com/questions/347729 UTF-8前提ですが、上記回答が多少参考になるかもしれません。 質問のソースの修正の為、コードが読みにくいかもしれません。 指摘があるように、ますば等倍フォントで表示されているか確認してみるのがいいと思います。
oimo0505

2022/09/12 13:53

Crimson_Tide様 コメントありがとうございます。 自己解決してしまったのですが、等倍フォントについても確認してみたいと思います!
jimbe

2022/09/12 16:52

ただのツッコミですが。 >Wallet.java  これと型の名前だけが違うクラスが各名目ごとにあります 分ける意味ありませんね。
guest

回答2

0

String.format の %s で文字数を指定した場合、Windows のコマンドラインプログラムを C で作った時の全角2/半角1のような動作(単に2バイト文字がたまたま半角2つ分のフォントだったとも)は無く、単純に unicode 1 文字単位で動作しているのでしょう。(char 2 つ以上使うコードの文字がどうなるのかは調べていません。)

ファイルを読んで表示するだけのコードとして全体を作り直してみました。
Windows のコマンドプロンプトで実行する前提として、 文字列を MS932 のバイト列に変換することで文字列全体の表示幅を得ています。
for で空白を必要数表示することで解決されたそうですが、今の java の String には repeat メソッドがありますのでそれを利用しています。

Main.java

java

1import java.io.*; 2import java.util.ArrayList; 3import java.util.List; 4 5public class Main { 6 public static void main(String[] args) throws IOException { 7 Item[] itemArray = load("PocketMoney.csv"); //"bookmoney/PocketMoney.csv" 8 showTable(itemArray); 9 } 10 11 static Item[] load(String filename) throws IOException { 12 try (BufferedReader br = new BufferedReader(new FileReader(filename))) { 13 List<Item> itemList = new ArrayList<>(); 14 for(String s; (s = br.readLine()) != null; ) { 15 String tokens[] = s.split(","); 16 if(tokens.length == 4) { 17 try { 18 itemList.add(new Item(tokens[0], tokens[1], tokens[2], tokens[3])); 19 } catch(IllegalArgumentException e) { 20 //ignore 21 } 22 } 23 } 24 return itemList.toArray(new Item[itemList.size()]); 25 } 26 } 27 28 static void showTable(Item[] itemArray) throws UnsupportedEncodingException { 29 int[] widths = new int[]{ 15, 14, 14, 6, 25 }; 30 31 drawTableRow(widths, "名目", "収入", "支出", "残額", "補足"); 32 drawTableLine(widths); 33 for(Item item : itemArray) { 34 drawTableRow(widths, item.getName(), item.getIncome(), item.getOutgo(), item.getAmount(), item.getNote()); 35 drawTableLine(widths); 36 } 37 } 38 static void drawTableRow(int[] widths, String... datas) throws UnsupportedEncodingException { 39 for(int i=0; i<widths.length; i++) { 40 System.out.print("|" + getLeftAlinment(widths[i], i<datas.length?datas[i]:"")); 41 } 42 System.out.println("|"); 43 } 44 static void drawTableLine(int[] widths) { 45 for(int w : widths) System.out.print("+" + "-".repeat(w)); 46 System.out.println("+"); 47 } 48 static String getLeftAlinment(int width, String str) throws UnsupportedEncodingException { 49 return str + " ".repeat(width - str.getBytes("MS932").length); 50 } 51 52 static class Item { 53 enum Flag {,; } 54 55 protected String name; 56 protected Flag flag; 57 protected String amount; 58 protected String note; 59 60 Item(String name, String flag, String amount, String note) { 61 this.name = name; 62 if((this.flag = Flag.valueOf(flag)) == null) throw new IllegalArgumentException("flag="+flag); 63 this.amount = amount; 64 this.note = note; 65 } 66 67 String getName() { return name; } 68 String getIncome() { return flag == Flag.? amount : ""; } 69 String getOutgo() { return flag == Flag.? amount : ""; } 70 String getAmount() { return ""; } 71 String getNote() { return note; } 72 } 73}

PocketMoney.csv

plain

1お財布,収,20000,N/A 2食費,支,2000,N/A 3書籍,支,1500,N/A 4日用品費,支,500,N/A 5お財布,収,5000,N/A 6お財布,収,1,N/A 7お財布,収,10000,N/A 8食費,支,10000,N/A

実行結果(teratail 上ではフォントの関係でズレ)

plain

1|名目 |収入 |支出 |残額 |補足 | 2+---------------+--------------+--------------+------+-------------------------+ 3|お財布 |20000 | | |N/A | 4+---------------+--------------+--------------+------+-------------------------+ 5|食費 | |2000 | |N/A | 6+---------------+--------------+--------------+------+-------------------------+ 7|書籍 | |1500 | |N/A | 8+---------------+--------------+--------------+------+-------------------------+ 9|日用品費 | |500 | |N/A | 10+---------------+--------------+--------------+------+-------------------------+ 11|お財布 |5000 | | |N/A | 12+---------------+--------------+--------------+------+-------------------------+ 13|お財布 |1 | | |N/A | 14+---------------+--------------+--------------+------+-------------------------+ 15|お財布 |10000 | | |N/A | 16+---------------+--------------+--------------+------+-------------------------+ 17|食費 | |10000 | |N/A | 18+---------------+--------------+--------------+------+-------------------------+

投稿2022/09/12 19:13

編集2022/09/13 10:57
jimbe

総合スコア12632

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

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

0

自己解決

空白の数を for文で連続表示させ変数に格納し、returnで返すことで空白埋めを行うことができました。

投稿2022/09/12 13:51

oimo0505

総合スコア22

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問