Java中的漂亮打印2D数组
我正在寻找一个将一个矩形String [] []打印到一个具有正确列长度的人类可读表中的util。
如果你想要类似于MySQL命令行客户端输出的东西,你可以使用类似的东西:
import java.io.PrintStream; import static java.lang.String.format; import static java.lang.System.out; public final class PrettyPrinter { private static final char BORDER_KNOT = '+'; private static final char HORIZONTAL_BORDER = '-'; private static final char VERTICAL_BORDER = '|'; private static final String DEFAULT_AS_NULL = "(NULL)"; private final PrintStream out; private final String asNull; public PrettyPrinter(PrintStream out) { this(out, DEFAULT_AS_NULL); } public PrettyPrinter(PrintStream out, String asNull) { if ( out == null ) { throw new IllegalArgumentException("No print stream provided"); } if ( asNull == null ) { throw new IllegalArgumentException("No NULL-value placeholder provided"); } this.out = out; this.asNull = asNull; } public void print(String[][] table) { if ( table == null ) { throw new IllegalArgumentException("No tabular data provided"); } if ( table.length == 0 ) { return; } final int[] widths = new int[getMaxColumns(table)]; adjustColumnWidths(table, widths); printPreparedTable(table, widths, getHorizontalBorder(widths)); } private void printPreparedTable(String[][] table, int widths[], String horizontalBorder) { final int lineLength = horizontalBorder.length(); out.println(horizontalBorder); for ( final String[] row : table ) { if ( row != null ) { out.println(getRow(row, widths, lineLength)); out.println(horizontalBorder); } } } private String getRow(String[] row, int[] widths, int lineLength) { final StringBuilder builder = new StringBuilder(lineLength).append(VERTICAL_BORDER); final int maxWidths = widths.length; for ( int i = 0; i < maxWidths; i++ ) { builder.append(padRight(getCellValue(safeGet(row, i, null)), widths[i])).append(VERTICAL_BORDER); } return builder.toString(); } private String getHorizontalBorder(int[] widths) { final StringBuilder builder = new StringBuilder(256); builder.append(BORDER_KNOT); for ( final int w : widths ) { for ( int i = 0; i < w; i++ ) { builder.append(HORIZONTAL_BORDER); } builder.append(BORDER_KNOT); } return builder.toString(); } private int getMaxColumns(String[][] rows) { int max = 0; for ( final String[] row : rows ) { if ( row != null && row.length > max ) { max = row.length; } } return max; } private void adjustColumnWidths(String[][] rows, int[] widths) { for ( final String[] row : rows ) { if ( row != null ) { for ( int c = 0; c < widths.length; c++ ) { final String cv = getCellValue(safeGet(row, c, asNull)); final int l = cv.length(); if ( widths[c] < l ) { widths[c] = l; } } } } } private static String padRight(String s, int n) { return format("%1$-" + n + "s", s); } private static String safeGet(String[] array, int index, String defaultValue) { return index < array.length ? array[index] : defaultValue; } private String getCellValue(Object value) { return value == null ? asNull : value.toString(); } }
并使用它:
final PrettyPrinter printer = new PrettyPrinter(out); printer.print(new String[][] { new String[] {"FIRST NAME", "LAST NAME", "DATE OF BIRTH", "NOTES"}, new String[] {"Joe", "Smith", "November 2, 1972"}, null, new String[] {"John", "Doe", "April 29, 1970", "Big Brother"}, new String[] {"Jack", null, null, "(yes, no last name)"}, });
上面的代码将产生以下输出:
+----------+---------+----------------+-------------------+ |FIRST NAME|LAST NAME|DATE OF BIRTH |NOTES | +----------+---------+----------------+-------------------+ |Joe |Smith |November 2, 1972|(NULL) | +----------+---------+----------------+-------------------+ |John |Doe |April 29, 1970 |Big Brother | +----------+---------+----------------+-------------------+ |Jack |(NULL) |(NULL) |(yes, no last name)| +----------+---------+----------------+-------------------+
我不知道一个可以执行此操作的util库,但您可以使用String.format函数来格式化字符串,因为您想要显示它们。 这是我很快写下的一个例子:
String[][] table = {{"Joe", "Bloggs", "18"}, {"Steve", "Jobs", "20"}, {"George", "Cloggs", "21"}}; for(int i=0; i<3; i++){ for(int j=0; j<3; j++){ System.out.print(String.format("%20s", table[i][j])); } System.out.println(""); }
这给出了以下输出:
Joe Bloggs 18 Steve Jobs 20 George Cloggs 21
你可以试试
System.out.println(Arrays.deepToString(someRectangularStringArray));
这就像没有特定代码那样漂亮。
JakWharton有一个很好的解决方案https://github.com/JakeWharton/flip-tables和格式String [],具有对属性名称和结果集的reflection的对象列表。 例如
List people = Arrays.asList(new Person("Foo", "Bar"), new Person("Kit", "Kat")); System.out.println(FlipTableConverters.fromIterable(people, Person.class));
因为我偶然发现了这个搜索即用型打印机(但不仅仅是针对Strings),我改变了Lyubomyr Shaydariv为接受的答案编写的代码。 由于这可能会增加问题的价值,我将分享它:
import static java.lang.String.format; public final class PrettyPrinter { private static final char BORDER_KNOT = '+'; private static final char HORIZONTAL_BORDER = '-'; private static final char VERTICAL_BORDER = '|'; private static final Printer
和Printer.java:
public interface Printer { String print(T obj); }
用法:
System.out.println(PrettyPrinter.print(some2dArray, new Printer() { @Override public String print(Integer obj) { return obj.toString(); } }));
为什么改为T
? Well String
还不够,但我并不总是希望obj.toString()
提供相同的输出,所以我使用该接口能够随意改变它。
第二个变化不是为类提供一个outstream
,如果你想使用类似Logger的类(Log4j // Logback),你肯定会遇到使用stream的问题。
为什么更改只支持静态调用? 我想将它用于记录器,只做一个电话似乎是明显的选择。
- 如何在相同的片段活动中将数据从片段发送到片段?
- Google Cloud Dataflow BigQueryIO.Write发生未知错误(http代码500)
- 如何将大输出写入Process getOutputStream?
- LocationManager在Android中的位置返回null
- Twitter认证后的CallBack
- 将“R.id.myID”从String转换为int值R.id.myID?
- 类构造函数无法在类加载上抛出exception
- 如何在Codename One Android项目中为build.gradle添加`apply plugin`以添加本机库?
- 非静态变量名称不能从静态上下文引用