2012-07-08 59 views

回答

19

如果你想類似於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)"}, 
}); 
0123上述

的代碼將產生以下輸出:

+----------+---------+----------------+-------------------+ 
|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)| 
+----------+---------+----------------+-------------------+ 
+0

謝謝,但沒有工作,有一條新線! – Hunsu 2014-07-07 07:19:44

+1

@ user230137是正確的,但這是MySQL輸出的工作方式。如果在本機MySQL命令行客戶端中進行SELECT查詢,並將結果導入帶有換行字符的行,則輸出也會中斷,因爲輸出字符不會以任何方式處理。唯一不同的是,我的實現更緊湊一些,因爲它不具有1個空格字符水平填充,而不像MySQL命令行輸出。 – 2014-07-09 10:09:58

8

您可以嘗試

System.out.println(Arrays.deepToString(someRectangularStringArray)); 

這就是漂亮,因爲它會得到不特定的代碼。

+0

那不是真的表 – 2012-07-08 15:47:36

+2

@DD。我知道它不是,但正如原來的問題是有點光明細節,我想指出這是(afaik)只有沒有代碼可能是足夠好的解決方案.... – fvu 2012-07-08 17:05:46

+0

好的解決方案,但要得到這個更漂亮的我不得不根據建議[這裏]使用進一步的'替換'結果(http://stackoverflow.com/questions/12845208#17423410)。 – 2016-08-17 12:50:08

9

我不知道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 
0

自從我偶然發現了這個尋找一個準備使用打印機(但不僅弦)我改變the accepted answer有點書面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<Object> DEFAULT = new Printer<Object>() { 
     @Override 
     public String print(Object obj) { 
      return obj.toString(); 
     } 
    }; 

    private static final String DEFAULT_AS_NULL = "(NULL)"; 

    public static String print(Object[][] table) { 
     return print(table, DEFAULT); 
    } 

    public static <T> String print(T[][] table, Printer<T> printer) { 
     if (table == null) { 
      throw new IllegalArgumentException("No tabular data provided"); 
     } 
     if (table.length == 0) { 
      return ""; 
     } 
     if(printer == null) { 
     throw new IllegalArgumentException("No instance of Printer provided"); 
     } 
     final int[] widths = new int[getMaxColumns(table)]; 
     adjustColumnWidths(table, widths, printer); 
     return printPreparedTable(table, widths, getHorizontalBorder(widths), printer); 
    } 

    private static <T> String printPreparedTable(T[][] table, int widths[], String horizontalBorder, Printer<T> printer) { 
     final int lineLength = horizontalBorder.length(); 
     StringBuilder sb = new StringBuilder(); 
     sb.append(horizontalBorder); 
     sb.append('\n'); 
     for (final T[] row : table) { 
      if (row != null) { 
       sb.append(getRow(row, widths, lineLength, printer)); 
       sb.append('\n'); 
       sb.append(horizontalBorder); 
       sb.append('\n'); 
      } 
     } 
     return sb.toString(); 
    } 

    private static <T> String getRow(T[] row, int[] widths, int lineLength, Printer<T> printer) { 
     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, printer), printer), widths[i])).append(VERTICAL_BORDER); 
     } 
     return builder.toString(); 
    } 

    private static 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 static int getMaxColumns(Object[][] rows) { 
     int max = 0; 
     for (final Object[] row : rows) { 
      if (row != null && row.length > max) { 
       max = row.length; 
      } 
     } 
     return max; 
    } 

    private static <T> void adjustColumnWidths(T[][] rows, int[] widths, Printer<T> printer) { 
     for (final T[] row : rows) { 
      if (row != null) { 
       for (int c = 0; c < widths.length; c++) { 
        final String cv = getCellValue(safeGet(row, c, printer), printer); 
        final int l = cv.length(); 
        if (widths[c] < l) { 
         widths[c] = l; 
        } 
       } 
      } 
     } 
    } 

    private static <T> String padRight(String s, int n) { 
     return format("%1$-" + n + "s", s); 
    } 

    private static <T> T safeGet(T[] array, int index, Printer<T> printer) { 
     return index < array.length ? array[index] : null; 
    } 

    private static <T> String getCellValue(T value, Printer<T> printer) { 
     return value == null ? DEFAULT_AS_NULL : printer.print(value); 
    } 

} 

而且Printer.java:

public interface Printer<T> { 
    String print(T obj); 
} 

用法:

System.out.println(PrettyPrinter.print(some2dArray, new Printer<Integer>() { 
     @Override 
     public String print(Integer obj) { 
      return obj.toString(); 
     } 
    })); 

爲什麼改變T?那麼String是不夠的,但我並不總是希望提供相同的輸出obj.toString()必須提供,所以我用界面能夠隨意改變。

第二個變化是不提供一個outstream類,如果你想用Logger這樣的類來使用類(Log4j // Logback),你肯定會遇到使用流的問題。

爲什麼更改只支持靜態調用?我想把它用於伐木工,只需要一個電話就顯而易見了。

+0

嗨。感謝您指出'T' - 我只考慮了'String'。關於返回String的靜態方法:我寧願提供一個寫入者回調注入或模仿一個PrintStream來寫入記錄器,因爲通常不需要獲得這樣的打印結果,但是有必要編寫它在某個地方沒有考慮將結果委託給可寫的適當對象。 – 2013-05-17 15:41:04

+0

另請注意,'String'是一般的表示類型。 'T'不是,只包含一個字段的類型,而不是記錄。因爲你可能想要處理一個對象列表,其中每個字段可以被轉換成一個String。如果你想漂亮地打印由'List '或'Person []'組成的行,那麼如何轉換然後打印'firstName'('String'),'lastName'('String'),' 'T'中分開的'dateOfBirth'('Date')字段?你可能會建議一個打印機接口返回String []或其他東西,但是在結果中總是會出現'String [] []'。 – 2013-05-17 16:10:22

+0

我不同意你在PrintStream上的第一個評論,因爲它與slf4j記錄器不兼容,但這可能是一場我不想涉及的聖戰(正如提議的靜態方法)。爲了回答你的問題,對於你放入PrettyPrinter的每個對象,調用Printer接口,在這裏你可以定義從T到String的任何轉換,其結果比原始的靈活性大得多。你可以迭代列表,如果每個字段都包含Person的列表。如果你沒有指定打印機T.toString()被調用。 – 2013-05-21 09:56:36

1

JakWharton有一個很好的解決方案https://github.com/JakeWharton/flip-tables和format String [],帶有反射屬性名稱和結果集的對象列表。例如

List<Person> people = Arrays.asList(new Person("Foo", "Bar"), new Person("Kit", "Kat")); 
System.out.println(FlipTableConverters.fromIterable(people, Person.class));