StringBuilder 看起来不错 table
Nice looking table with StringBuilder
我知道 "printf" 方法可以使用字符串格式。
我的问题是:
有没有办法用 StringBuilder class 创建一个漂亮的 table?
例如:
|Id|Category|Level|Space|Type|Adress|Dimension|Limits|
在该行下,我必须添加每列的值!
做类似的事情:example 但使用 StringBuilder
所以社区希望看到我的答案(我不明白为什么......但无论如何我都会说!)
public String toString(){
StringBuilder s = new StringBuilder();
s.append("Category: "+this.category+"\t");
s.append("Level: "+this.level.toString()+"\t");
return s.toString();
}
现在解释一下,为什么看到我的回答会对我有帮助?我真的很想看到你的回答!
当然,一种简单的方法是创建硬连接的 printf
语句。但是,这不是很灵活,因为您总是必须固定列宽,并且函数总是特定于一个 class 及其字段。
所以我想推荐一个助手class,主要做两件事:
- 封装 table 单元格条目的创建(通过 Java 8
Function
)
- 计算给定元素集的每列的最大宽度。
假设有一个给定的模型class,比如Person
,例如:
class Person
{
int getId() { ... }
String getFirstName() { ... }
String getLastName() { ... }
float getHeight() { ... }
}
然后,我想创建一个 "nice" table 如下:
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
而且我希望此字符串的内容格式正确 table:
id| first name| last name|height
-----+-------------+-------------+------
41360|Xvnjhpdqdxvcr| Stvybcwvm| 1.7
3503| Krxvzxk| Xtspsjd| 1.6
41198| Uegqfl| Qlocfljbepo| 1.58
26517| Somyar| Aopufo| 1.77
13773| Dxehxjbhwgsm| Jgnlonjv| 1.77
13067| Zozitk| Jbozwd| 1.81
46534| Bosyq| Kcprrdc| 1.55
93862| Rlfxblgqp| Pgrntaqoos| 1.85
12155| Kjpjlavsqc|Rxfrrollhwhoh| 1.79
75712| Fwpnd| Mwcsshwx| 1.78
a MVCE 显示了这样一个 TableStringBuilder
及其应用:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
public class TableStringTest
{
public static void main(String[] args)
{
List<Person> persons = new ArrayList<Person>();
for (int i=0; i<10; i++)
{
persons.add(new Person());
}
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
System.out.println(s);
}
}
class TableStringBuilder<T>
{
private final List<String> columnNames;
private final List<Function<? super T, String>> stringFunctions;
TableStringBuilder()
{
columnNames = new ArrayList<String>();
stringFunctions = new ArrayList<Function<? super T, String>>();
}
void addColumn(String columnName, Function<? super T, ?> fieldFunction)
{
columnNames.add(columnName);
stringFunctions.add((p) -> (String.valueOf(fieldFunction.apply(p))));
}
private int computeMaxWidth(int column, Iterable<? extends T> elements)
{
int n = columnNames.get(column).length();
Function<? super T, String> f = stringFunctions.get(column);
for (T element : elements)
{
String s = f.apply(element);
n = Math.max(n, s.length());
}
return n;
}
private static String padLeft(String s, char c, int length)
{
while (s.length() < length)
{
s = c + s;
}
return s;
}
private List<Integer> computeColumnWidths(Iterable<? extends T> elements)
{
List<Integer> columnWidths = new ArrayList<Integer>();
for (int c=0; c<columnNames.size(); c++)
{
int maxWidth = computeMaxWidth(c, elements);
columnWidths.add(maxWidth);
}
return columnWidths;
}
public String createString(Iterable<? extends T> elements)
{
List<Integer> columnWidths = computeColumnWidths(elements);
StringBuilder sb = new StringBuilder();
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
sb.append(String.format(format, columnNames.get(c)));
}
sb.append("\n");
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("+");
}
sb.append(padLeft("", '-', columnWidths.get(c)));
}
sb.append("\n");
for (T element : elements)
{
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
Function<? super T, String> f = stringFunctions.get(c);
String s = f.apply(element);
sb.append(String.format(format, s));
}
sb.append("\n");
}
return sb.toString();
}
}
//Dummy Person Class
class Person
{
private int id;
private String firstName;
private String lastName;
private float height;
private static Random random = new Random(0);
Person()
{
id = random.nextInt(100000);
firstName = createRandomString();
lastName = createRandomString();
height = (150 + random.nextInt(40)) / 100.0f;
}
private static String createRandomString()
{
int length = random.nextInt(10) + 5;
StringBuilder sb = new StringBuilder();
char offset = 'A';
for (int i=0; i<length; i++)
{
char c = (char)(random.nextInt(26) + offset);
sb.append(c);
offset = 'a';
}
return sb.toString();
}
int getId()
{
return id;
}
String getFirstName()
{
return firstName;
}
String getLastName()
{
return lastName;
}
float getHeight()
{
return height;
}
}
好的,谢谢大家对我很好的回答。
我发现我们可以那样做:
public String toString(){
StringBuilder s = new StringBuilder();
s.append(String.format("%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n","Identifier","Category","Level","Space","Type","Dimension","Limits"));
s.append(String.format("=============================================================================================================================================\n"));
for(String id : this.idTable.keySet()) {
s.append(String.format("%-20s",id));
s.append(this.idTable.get(id).toString());
//s.append("Identifier: " +id+" "+this.idTable.get(id).toString()+"\n");
}
return s.toString();
}
注意,String.format
完成了我之前不知道的所有工作!
问候你@Marco13,你做得很好 !!!!
谢谢大家!
P.S.: 我会同意@Marco13 的消息,因为他的实现也非常好!
我知道 "printf" 方法可以使用字符串格式。
我的问题是: 有没有办法用 StringBuilder class 创建一个漂亮的 table?
例如:
|Id|Category|Level|Space|Type|Adress|Dimension|Limits|
在该行下,我必须添加每列的值!
做类似的事情:example 但使用 StringBuilder
所以社区希望看到我的答案(我不明白为什么......但无论如何我都会说!)
public String toString(){
StringBuilder s = new StringBuilder();
s.append("Category: "+this.category+"\t");
s.append("Level: "+this.level.toString()+"\t");
return s.toString();
}
现在解释一下,为什么看到我的回答会对我有帮助?我真的很想看到你的回答!
当然,一种简单的方法是创建硬连接的 printf
语句。但是,这不是很灵活,因为您总是必须固定列宽,并且函数总是特定于一个 class 及其字段。
所以我想推荐一个助手class,主要做两件事:
- 封装 table 单元格条目的创建(通过 Java 8
Function
) - 计算给定元素集的每列的最大宽度。
假设有一个给定的模型class,比如Person
,例如:
class Person
{
int getId() { ... }
String getFirstName() { ... }
String getLastName() { ... }
float getHeight() { ... }
}
然后,我想创建一个 "nice" table 如下:
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
而且我希望此字符串的内容格式正确 table:
id| first name| last name|height
-----+-------------+-------------+------
41360|Xvnjhpdqdxvcr| Stvybcwvm| 1.7
3503| Krxvzxk| Xtspsjd| 1.6
41198| Uegqfl| Qlocfljbepo| 1.58
26517| Somyar| Aopufo| 1.77
13773| Dxehxjbhwgsm| Jgnlonjv| 1.77
13067| Zozitk| Jbozwd| 1.81
46534| Bosyq| Kcprrdc| 1.55
93862| Rlfxblgqp| Pgrntaqoos| 1.85
12155| Kjpjlavsqc|Rxfrrollhwhoh| 1.79
75712| Fwpnd| Mwcsshwx| 1.78
a MVCE 显示了这样一个 TableStringBuilder
及其应用:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
public class TableStringTest
{
public static void main(String[] args)
{
List<Person> persons = new ArrayList<Person>();
for (int i=0; i<10; i++)
{
persons.add(new Person());
}
TableStringBuilder<Person> t = new TableStringBuilder<Person>();
t.addColumn("id", Person::getId);
t.addColumn("first name", Person::getFirstName);
t.addColumn("last name", Person::getLastName);
t.addColumn("height", Person::getHeight);
String s = t.createString(persons);
System.out.println(s);
}
}
class TableStringBuilder<T>
{
private final List<String> columnNames;
private final List<Function<? super T, String>> stringFunctions;
TableStringBuilder()
{
columnNames = new ArrayList<String>();
stringFunctions = new ArrayList<Function<? super T, String>>();
}
void addColumn(String columnName, Function<? super T, ?> fieldFunction)
{
columnNames.add(columnName);
stringFunctions.add((p) -> (String.valueOf(fieldFunction.apply(p))));
}
private int computeMaxWidth(int column, Iterable<? extends T> elements)
{
int n = columnNames.get(column).length();
Function<? super T, String> f = stringFunctions.get(column);
for (T element : elements)
{
String s = f.apply(element);
n = Math.max(n, s.length());
}
return n;
}
private static String padLeft(String s, char c, int length)
{
while (s.length() < length)
{
s = c + s;
}
return s;
}
private List<Integer> computeColumnWidths(Iterable<? extends T> elements)
{
List<Integer> columnWidths = new ArrayList<Integer>();
for (int c=0; c<columnNames.size(); c++)
{
int maxWidth = computeMaxWidth(c, elements);
columnWidths.add(maxWidth);
}
return columnWidths;
}
public String createString(Iterable<? extends T> elements)
{
List<Integer> columnWidths = computeColumnWidths(elements);
StringBuilder sb = new StringBuilder();
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
sb.append(String.format(format, columnNames.get(c)));
}
sb.append("\n");
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("+");
}
sb.append(padLeft("", '-', columnWidths.get(c)));
}
sb.append("\n");
for (T element : elements)
{
for (int c=0; c<columnNames.size(); c++)
{
if (c > 0)
{
sb.append("|");
}
String format = "%"+columnWidths.get(c)+"s";
Function<? super T, String> f = stringFunctions.get(c);
String s = f.apply(element);
sb.append(String.format(format, s));
}
sb.append("\n");
}
return sb.toString();
}
}
//Dummy Person Class
class Person
{
private int id;
private String firstName;
private String lastName;
private float height;
private static Random random = new Random(0);
Person()
{
id = random.nextInt(100000);
firstName = createRandomString();
lastName = createRandomString();
height = (150 + random.nextInt(40)) / 100.0f;
}
private static String createRandomString()
{
int length = random.nextInt(10) + 5;
StringBuilder sb = new StringBuilder();
char offset = 'A';
for (int i=0; i<length; i++)
{
char c = (char)(random.nextInt(26) + offset);
sb.append(c);
offset = 'a';
}
return sb.toString();
}
int getId()
{
return id;
}
String getFirstName()
{
return firstName;
}
String getLastName()
{
return lastName;
}
float getHeight()
{
return height;
}
}
好的,谢谢大家对我很好的回答。
我发现我们可以那样做:
public String toString(){
StringBuilder s = new StringBuilder();
s.append(String.format("%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n","Identifier","Category","Level","Space","Type","Dimension","Limits"));
s.append(String.format("=============================================================================================================================================\n"));
for(String id : this.idTable.keySet()) {
s.append(String.format("%-20s",id));
s.append(this.idTable.get(id).toString());
//s.append("Identifier: " +id+" "+this.idTable.get(id).toString()+"\n");
}
return s.toString();
}
注意,String.format
完成了我之前不知道的所有工作!
问候你@Marco13,你做得很好 !!!! 谢谢大家!
P.S.: 我会同意@Marco13 的消息,因为他的实现也非常好!