/** * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.collect.io; import java.util.List; import com.google.common.base.Strings; import com.opengamma.strata.collect.ArgChecker; /** * An ASCII table generator. * <p> * Provides the ability to generate a simple ASCII table, typically used on the command line. * All data is provided as strings, with formatting the responsibility of the caller. */ public final class AsciiTable { /** * Line separator. */ private static final String LINE_SEPARATOR = System.lineSeparator(); //------------------------------------------------------------------------- /** * Generates the ASCII table. * <p> * The caller specifies the headers for each column and the alignment to use, * plus the list of lists representing the data. All data is provided as strings, * with formatting the responsibility of the caller. * * @param headers the table headers * @param alignments the table alignments, must match the size of the headers * @param cells the table cells, outer list of rows, inner list of columns * @return the table * @throws IllegalArgumentException if the number of columns specified is inconsistent */ public static String generate( List<String> headers, List<AsciiTableAlignment> alignments, List<? extends List<String>> cells) { int colCount = alignments.size(); int rowCount = cells.size(); ArgChecker.isTrue( headers.size() == colCount, "Number of headers {} must match number of alignments {}", headers.size(), colCount); // find max length of each column int[] colLengths = new int[colCount]; for (int colIdx = 0; colIdx < colCount; colIdx++) { colLengths[colIdx] = headers.get(colIdx).length(); } for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) { List<String> row = cells.get(rowIdx); ArgChecker.isTrue( row.size() == colCount, "Table of cells has incorrect number of columns {} in row {}", row.size(), rowIdx); for (int colIdx = 0; colIdx < colCount; colIdx++) { colLengths[colIdx] = Math.max(colLengths[colIdx], row.get(colIdx).length()); } } int colTotalLength = 3; // allow for last vertical separator and windows line separator for (int colIdx = 0; colIdx < colCount; colIdx++) { colTotalLength += colLengths[colIdx] + 3; // each column has two spaces and a vertical separator } // write table StringBuilder buf = new StringBuilder((rowCount + 3) * colTotalLength); writeSeparatorLine(buf, colLengths); writeDataLine(buf, colLengths, alignments, headers); writeSeparatorLine(buf, colLengths); for (int rowIdx = 0; rowIdx < rowCount; rowIdx++) { writeDataLine(buf, colLengths, alignments, cells.get(rowIdx)); } writeSeparatorLine(buf, colLengths); return buf.toString(); } // write a separator line private static void writeSeparatorLine(StringBuilder buf, int[] colLengths) { for (int colIdx = 0; colIdx < colLengths.length; colIdx++) { buf.append('+'); for (int i = 0; i < colLengths[colIdx] + 2; i++) { buf.append('-'); } } buf.append('+').append(LINE_SEPARATOR); } // write a data line private static void writeDataLine( StringBuilder buf, int[] colLengths, List<AsciiTableAlignment> alignments, List<String> values) { for (int colIdx = 0; colIdx < colLengths.length; colIdx++) { String value = Strings.nullToEmpty(values.get(colIdx)); buf.append('|') .append(' ') .append(formatValue(buf, colLengths[colIdx], alignments.get(colIdx), value)) .append(' '); } buf.append('|').append(LINE_SEPARATOR); } // writes a data item private static String formatValue( StringBuilder buf, int colLength, AsciiTableAlignment alignment, String value) { if (alignment == AsciiTableAlignment.RIGHT) { return Strings.padStart(value, colLength, ' '); } else { return Strings.padEnd(value, colLength, ' '); } } //------------------------------------------------------------------------- /** * Restricted constructor. */ private AsciiTable() { } }