summaryrefslogtreecommitdiff
path: root/src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java')
-rw-r--r--src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java959
1 files changed, 959 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java b/src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java
new file mode 100644
index 00000000..9545e25a
--- /dev/null
+++ b/src/de/lmu/ifi/dbs/elki/utilities/FormatUtil.java
@@ -0,0 +1,959 @@
+package de.lmu.ifi.dbs.elki.utilities;
+/*
+This file is part of ELKI:
+Environment for Developing KDD-Applications Supported by Index-Structures
+
+Copyright (C) 2011
+Ludwig-Maximilians-Universität München
+Lehr- und Forschungseinheit für Datenbanksysteme
+ELKI Development Team
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+
+import de.lmu.ifi.dbs.elki.math.linearalgebra.Matrix;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.MatrixLike;
+import de.lmu.ifi.dbs.elki.math.linearalgebra.Vector;
+
+/**
+ * Utility methods for output formatting of various number objects
+ */
+public final class FormatUtil {
+ /**
+ * Dynamic number formatter, but with language constraint.
+ */
+ public static final NumberFormat NF = NumberFormat.getInstance(Locale.US);
+
+ /**
+ * Number Formatter (2 digits) for output purposes.
+ */
+ public static final NumberFormat NF2 = NumberFormat.getInstance(Locale.US);
+
+ /**
+ * Number Formatter (4 digits) for output purposes.
+ */
+ public static final NumberFormat NF4 = NumberFormat.getInstance(Locale.US);
+
+ /**
+ * Number Formatter (6 digits) for output purposes.
+ */
+ public static final NumberFormat NF6 = NumberFormat.getInstance(Locale.US);
+
+ /**
+ * Number Formatter (8 digits) for output purposes.
+ */
+ public static final NumberFormat NF8 = NumberFormat.getInstance(Locale.US);
+
+ static {
+ NF.setMinimumFractionDigits(0);
+ NF.setMaximumFractionDigits(10);
+ NF.setGroupingUsed(false);
+ NF2.setMinimumFractionDigits(2);
+ NF2.setMaximumFractionDigits(2);
+ NF2.setGroupingUsed(false);
+ NF4.setMinimumFractionDigits(4);
+ NF4.setMaximumFractionDigits(4);
+ NF4.setGroupingUsed(false);
+ NF6.setMinimumFractionDigits(6);
+ NF6.setMaximumFractionDigits(6);
+ NF6.setGroupingUsed(false);
+ NF8.setMinimumFractionDigits(8);
+ NF8.setMaximumFractionDigits(8);
+ NF8.setGroupingUsed(false);
+ }
+
+ /**
+ * Whitespace. The string should cover the commonly used length.
+ */
+ private static final String WHITESPACE_BUFFER = " ";
+
+ /**
+ * The system newline setting.
+ */
+ public static final String NEWLINE = System.getProperty("line.separator");
+
+ /**
+ * Non-breaking unicode space character.
+ */
+ public static final String NONBREAKING_SPACE = "\u00a0";
+
+ /**
+ * The time unit sizes: ms, s, m, h, d; all in ms.
+ */
+ private static final long[] TIME_UNIT_SIZES = new long[] { 1L, 1000L, 60000L, 3600000L, 86400000L };
+
+ /**
+ * The strings used in serialization
+ */
+ private static final String[] TIME_UNIT_NAMES = new String[] { "ms", "s", "m", "h", "d" };
+
+ /**
+ * The number of digits used for formatting
+ */
+ private static final int[] TIME_UNIT_DIGITS = new int[] { 3, 2, 2, 2, 2 };
+
+ /**
+ * Formats the double d with the specified fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @param digits the number of fraction digits
+ * @return a String representing the double d
+ */
+ public static String format(final double d, int digits) {
+ final NumberFormat nf = NumberFormat.getInstance(Locale.US);
+ nf.setMaximumFractionDigits(digits);
+ nf.setMinimumFractionDigits(digits);
+ nf.setGroupingUsed(false);
+ return nf.format(d);
+ }
+
+ /**
+ * Formats the double d with the specified number format.
+ *
+ * @param d the double array to be formatted
+ * @param nf the number format to be used for formatting
+ * @return a String representing the double d
+ */
+ public static String format(final double d, NumberFormat nf) {
+ return nf.format(d);
+ }
+
+ /**
+ * Formats the double d with 2 fraction digits.
+ *
+ * @param d the double to be formatted
+ * @return a String representing the double d
+ */
+ public static String format(final double d) {
+ return format(d, 2);
+ }
+
+ /**
+ * Formats the double array d with the specified separator.
+ *
+ * @param d the double array to be formatted
+ * @param sep the separator between the single values of the double array,
+ * e.g. ','
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d, String sep) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < d.length; i++) {
+ if(i > 0) {
+ buffer.append(sep).append(d[i]);
+ }
+ else {
+ buffer.append(d[i]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the double array d with the specified separator and the specified
+ * fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @param sep the separator between the single values of the double array,
+ * e.g. ','
+ * @param digits the number of fraction digits
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d, String sep, int digits) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < d.length; i++) {
+ if(i < d.length - 1) {
+ buffer.append(format(d[i], digits)).append(sep);
+ }
+ else {
+ buffer.append(format(d[i], digits));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the double array d with the specified number format.
+ *
+ * @param d the double array to be formatted
+ * @param nf the number format to be used for formatting
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d, NumberFormat nf) {
+ return format(d, " ", nf);
+ }
+
+ /**
+ * Formats the double array d with the specified number format.
+ *
+ * @param d the double array to be formatted
+ * @param sep the separator between the single values of the double array,
+ * e.g. ','
+ * @param nf the number format to be used for formatting
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d, String sep, NumberFormat nf) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < d.length; i++) {
+ if(i < d.length - 1) {
+ buffer.append(format(d[i], nf)).append(sep);
+ }
+ else {
+ buffer.append(format(d[i], nf));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the double array d with ',' as separator and 2 fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d) {
+ return format(d, ", ", 2);
+ }
+
+ /**
+ * Formats the double array d with ', ' as separator and with the specified
+ * fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @param digits the number of fraction digits
+ * @return a String representing the double array d
+ */
+ public static String format(double[] d, int digits) {
+ return format(d, ", ", digits);
+ }
+
+ /**
+ * Formats the double array d with ',' as separator and 2 fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @return a String representing the double array d
+ */
+ public static String format(double[][] d) {
+ StringBuffer buffer = new StringBuffer();
+ for(double[] array : d) {
+ buffer.append(format(array, ", ", 2)).append("\n");
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the array of double arrays d with 'the specified separators and
+ * fraction digits.
+ *
+ * @param d the double array to be formatted
+ * @param sep1 the first separator of the outer array
+ * @param sep2 the second separator of the inner array
+ * @param digits the number of fraction digits
+ * @return a String representing the double array d
+ */
+ public static String format(double[][] d, String sep1, String sep2, int digits) {
+ StringBuffer buffer = new StringBuffer();
+
+ for(int i = 0; i < d.length; i++) {
+ if(i < d.length - 1) {
+ buffer.append(format(d[i], sep2, digits)).append(sep1);
+ }
+ else {
+ buffer.append(format(d[i], sep2, digits));
+ }
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the Double array f with the specified separator and the specified
+ * fraction digits.
+ *
+ * @param f the Double array to be formatted
+ * @param sep the separator between the single values of the Double array,
+ * e.g. ','
+ * @param digits the number of fraction digits
+ * @return a String representing the Double array f
+ */
+ public static String format(Double[] f, String sep, int digits) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < f.length; i++) {
+ if(i < f.length - 1) {
+ buffer.append(format(f[i], digits)).append(sep);
+ }
+ else {
+ buffer.append(format(f[i], digits));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the Double array f with ',' as separator and 2 fraction digits.
+ *
+ * @param f the Double array to be formatted
+ * @return a String representing the Double array f
+ */
+ public static String format(Double[] f) {
+ return format(f, ", ", 2);
+ }
+
+ /**
+ * Formats the Double array f with the specified separator and the specified
+ * fraction digits.
+ *
+ * @param f the Double array to be formatted
+ * @param sep the separator between the single values of the Double array,
+ * e.g. ','
+ * @param nf the number format
+ * @return a String representing the Double array f
+ */
+ public static String format(Double[] f, String sep, NumberFormat nf) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < f.length; i++) {
+ if(i < f.length - 1) {
+ buffer.append(format(f[i], nf)).append(sep);
+ }
+ else {
+ buffer.append(format(f[i], nf));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the Double array f with ',' as separator and 2 fraction digits.
+ *
+ * @param f the Double array to be formatted
+ * @param nf the Number format
+ * @return a String representing the Double array f
+ */
+ public static String format(Double[] f, NumberFormat nf) {
+ return format(f, ", ", nf);
+ }
+
+ /**
+ * Formats the float array f with the specified separator and the specified
+ * fraction digits.
+ *
+ * @param f the float array to be formatted
+ * @param sep the separator between the single values of the float array, e.g.
+ * ','
+ * @param digits the number of fraction digits
+ * @return a String representing the float array f
+ */
+ public static String format(float[] f, String sep, int digits) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < f.length; i++) {
+ if(i < f.length - 1) {
+ buffer.append(format(f[i], digits)).append(sep);
+ }
+ else {
+ buffer.append(format(f[i], digits));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the float array f with ',' as separator and 2 fraction digits.
+ *
+ * @param f the float array to be formatted
+ * @return a String representing the float array f
+ */
+ public static String format(float[] f) {
+ return format(f, ", ", 2);
+ }
+
+ /**
+ * Formats the int array a for printing purposes.
+ *
+ * @param a the int array to be formatted
+ * @param sep the separator between the single values of the float array, e.g.
+ * ','
+ * @return a String representing the int array a
+ */
+ public static String format(int[] a, String sep) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < a.length; i++) {
+ if(i < a.length - 1) {
+ buffer.append(a[i]).append(sep);
+ }
+ else {
+ buffer.append(a[i]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the int array a for printing purposes.
+ *
+ * @param a the int array to be formatted
+ * @return a String representing the int array a
+ */
+ public static String format(int[] a) {
+ return format(a, ", ");
+ }
+
+ /**
+ * Formats the Integer array a for printing purposes.
+ *
+ * @param a the Integer array to be formatted
+ * @param sep the separator between the single values of the float array, e.g.
+ * ','
+ * @return a String representing the Integer array a
+ */
+ public static String format(Integer[] a, String sep) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < a.length; i++) {
+ if(i < a.length - 1) {
+ buffer.append(a[i]).append(sep);
+ }
+ else {
+ buffer.append(a[i]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the Integer array a for printing purposes.
+ *
+ * @param a the Integer array to be formatted
+ * @return a String representing the Integer array a
+ */
+ public static String format(Integer[] a) {
+ return format(a, ", ");
+ }
+
+ /**
+ * Formats the long array a for printing purposes.
+ *
+ * @param a the long array to be formatted
+ * @return a String representing the long array a
+ */
+ public static String format(long[] a) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < a.length; i++) {
+ if(i < a.length - 1) {
+ buffer.append(a[i]).append(", ");
+ }
+ else {
+ buffer.append(a[i]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the byte array a for printing purposes.
+ *
+ * @param a the byte array to be formatted
+ * @return a String representing the byte array a
+ */
+ public static String format(byte[] a) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < a.length; i++) {
+ if(i < a.length - 1) {
+ buffer.append(a[i]).append(", ");
+ }
+ else {
+ buffer.append(a[i]);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the boolean array b with ',' as separator.
+ *
+ * @param b the boolean array to be formatted
+ * @param sep the separator between the single values of the double array,
+ * e.g. ','
+ * @return a String representing the boolean array b
+ */
+ public static String format(boolean[] b, final String sep) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < b.length; i++) {
+ if(i < b.length - 1) {
+ buffer.append(format(b[i])).append(sep);
+ }
+ else {
+ buffer.append(format(b[i]));
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Formats the boolean b.
+ *
+ * @param b the boolean to be formatted
+ * @return a String representing of the boolean b
+ */
+ public static String format(final boolean b) {
+ if(b) {
+ return "1";
+ }
+ return "0";
+ }
+
+ /**
+ * Returns a string representation of the specified bit set.
+ *
+ * @param bitSet the bitSet
+ * @param dim the overall dimensionality of the bit set
+ * @param sep the separator
+ * @return a string representation of the specified bit set.
+ */
+ public static String format(BitSet bitSet, int dim, String sep) {
+ StringBuffer msg = new StringBuffer();
+
+ for(int d = 0; d < dim; d++) {
+ if(d > 0) {
+ msg.append(sep);
+ }
+ if(bitSet.get(d)) {
+ msg.append("1");
+ }
+ else {
+ msg.append("0");
+ }
+ }
+
+ return msg.toString();
+ }
+
+ /**
+ * Returns a string representation of the specified bit set.
+ *
+ * @param dim the overall dimensionality of the bit set
+ * @param bitSet the bitSet
+ * @return a string representation of the specified bit set.
+ */
+ public static String format(int dim, BitSet bitSet) {
+ // TODO: removed whitespace - hierarchy reading to be adapted!
+ return format(bitSet, dim, ",");
+ }
+
+ /**
+ * Formats the String collection with the specified separator.
+ *
+ * @param d the String collection to format
+ * @param sep the separator between the single values of the double array,
+ * e.g. ' '
+ * @return a String representing the String Collection d
+ */
+ public static String format(Collection<String> d, String sep) {
+ if(d.size() == 0) {
+ return "";
+ }
+ if(d.size() == 1) {
+ return d.iterator().next();
+ }
+ StringBuffer buffer = new StringBuffer();
+ boolean first = true;
+ for(String str : d) {
+ if(!first) {
+ buffer.append(sep);
+ }
+ buffer.append(str);
+ first = false;
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns a string representation of this matrix.
+ *
+ * @param w column width
+ * @param d number of digits after the decimal
+ * @return a string representation of this matrix
+ */
+ // TODO: in use?
+ public static String format(MatrixLike<?> m, int w, int d) {
+ DecimalFormat format = new DecimalFormat();
+ format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
+ format.setMinimumIntegerDigits(1);
+ format.setMaximumFractionDigits(d);
+ format.setMinimumFractionDigits(d);
+ format.setGroupingUsed(false);
+
+ int width = w + 1;
+ StringBuffer msg = new StringBuffer();
+ msg.append("\n"); // start on new line.
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ String s = format.format(m.get(i, j)); // format the number
+ int padding = Math.max(1, width - s.length()); // At _least_ 1
+ // space
+ for(int k = 0; k < padding; k++) {
+ msg.append(' ');
+ }
+ msg.append(s);
+ }
+ msg.append("\n");
+ }
+ // msg.append("\n");
+
+ return msg.toString();
+ }
+
+ /**
+ * Returns a string representation of this matrix. In each line the specified
+ * String <code>pre</code> is prefixed.
+ *
+ * @param pre the prefix of each line
+ * @return a string representation of this matrix
+ */
+ public static String format(MatrixLike<?> m, String pre) {
+ StringBuffer output = new StringBuffer();
+ output.append(pre).append("[\n").append(pre);
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ output.append(" [");
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ output.append(" ").append(m.get(i, j));
+ if(j < m.getColumnDimensionality() - 1) {
+ output.append(",");
+ }
+ }
+ output.append(" ]\n").append(pre);
+ }
+ output.append("]\n").append(pre);
+
+ return (output.toString());
+ }
+
+ /**
+ * returns String-representation of Matrix.
+ *
+ * @param nf NumberFormat to specify output precision
+ * @return String representation of this Matrix in precision as specified by
+ * given NumberFormat
+ */
+ public static String format(Matrix m, NumberFormat nf) {
+ int[] colMax = new int[m.getColumnDimensionality()];
+ String[][] entries = new String[m.getRowDimensionality()][m.getColumnDimensionality()];
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ entries[i][j] = nf.format(m.get(i, j));
+ if(entries[i][j].length() > colMax[j]) {
+ colMax[j] = entries[i][j].length();
+ }
+ }
+ }
+ StringBuffer output = new StringBuffer();
+ output.append("[\n");
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ output.append(" [");
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ output.append(" ");
+ int space = colMax[j] - entries[i][j].length();
+ for(int s = 0; s < space; s++) {
+ output.append(" ");
+ }
+ output.append(entries[i][j]);
+ if(j < m.getColumnDimensionality() - 1) {
+ output.append(",");
+ }
+ }
+ output.append(" ]\n");
+ }
+ output.append("]\n");
+
+ return (output.toString());
+ }
+
+ /**
+ * returns String-representation of Matrix.
+ *
+ * @return String representation of this Matrix
+ */
+ public static String format(Matrix m) {
+ return format(m, FormatUtil.NF8);
+ }
+
+ /**
+ * returns String-representation of Vector.
+ *
+ * @param nf NumberFormat to specify output precision
+ * @return String representation of this Matrix in precision as specified by
+ * given NumberFormat
+ */
+ public static String format(Vector m, NumberFormat nf) {
+ return "[" + FormatUtil.format(m.getArrayRef(), nf) + "]";
+ }
+
+ /**
+ * Returns String-representation of Vector.
+ *
+ * @return String representation of this Vector
+ */
+ public static String format(Vector m) {
+ return format(m, FormatUtil.NF8);
+ }
+
+ /**
+ * Returns a string representation of this matrix. In each line the specified
+ * String <code>pre<\code> is prefixed.
+ *
+ * @param nf number format for output accuracy
+ * @param pre the prefix of each line
+ * @return a string representation of this matrix
+ */
+ public static String format(MatrixLike<?> m, String pre, NumberFormat nf) {
+ if(nf == null) {
+ return FormatUtil.format(m, pre);
+ }
+
+ int[] colMax = new int[m.getColumnDimensionality()];
+ String[][] entries = new String[m.getRowDimensionality()][m.getColumnDimensionality()];
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ entries[i][j] = nf.format(m.get(i, j));
+ if(entries[i][j].length() > colMax[j]) {
+ colMax[j] = entries[i][j].length();
+ }
+ }
+ }
+ StringBuffer output = new StringBuffer();
+ output.append(pre).append("[\n").append(pre);
+ for(int i = 0; i < m.getRowDimensionality(); i++) {
+ output.append(" [");
+ for(int j = 0; j < m.getColumnDimensionality(); j++) {
+ output.append(" ");
+ int space = colMax[j] - entries[i][j].length();
+ for(int s = 0; s < space; s++) {
+ output.append(" ");
+ }
+ output.append(entries[i][j]);
+ if(j < m.getColumnDimensionality() - 1) {
+ output.append(",");
+ }
+ }
+ output.append(" ]\n").append(pre);
+ }
+ output.append("]\n").append(pre);
+
+ return (output.toString());
+ }
+
+ /**
+ * Find the first space before position w or if there is none after w.
+ *
+ * @param s String
+ * @param width Width
+ * @return index of best whitespace or <code>-1</code> if no whitespace was
+ * found.
+ */
+ public static int findSplitpoint(String s, int width) {
+ // the newline (or EOS) is the fallback split position.
+ int in = s.indexOf(NEWLINE);
+ if(in < 0) {
+ in = s.length();
+ }
+ // Good enough?
+ if(in < width) {
+ return in;
+ }
+ // otherwise, search for whitespace
+ int iw = s.lastIndexOf(' ', width);
+ // good whitespace found?
+ if(iw >= 0 && iw < width) {
+ return iw;
+ }
+ // sub-optimal splitpoint - retry AFTER the given position
+ int bp = nextPosition(s.indexOf(' ', width), s.indexOf(NEWLINE, width));
+ if(bp >= 0) {
+ return bp;
+ }
+ // even worse - can't split!
+ return s.length();
+ }
+
+ /**
+ * Helper that is similar to {@code Math.min(a,b)}, except that negative
+ * values are considered "invalid".
+ *
+ * @param a String position
+ * @param b String position
+ * @return {@code Math.min(a,b)} if {@code a >= 0} and {@code b >= 0},
+ * otherwise whichever is positive.
+ */
+ private static int nextPosition(int a, int b) {
+ if(a < 0) {
+ return b;
+ }
+ if(b < 0) {
+ return a;
+ }
+ return Math.min(a, b);
+ }
+
+ /**
+ * Splits the specified string at the last blank before width. If there is no
+ * blank before the given width, it is split at the next.
+ *
+ * @param s the string to be split
+ * @param width int
+ * @return string fragments
+ */
+ public static List<String> splitAtLastBlank(String s, int width) {
+ List<String> chunks = new ArrayList<String>();
+
+ String tmp = s;
+ while(tmp.length() > 0) {
+ int index = findSplitpoint(tmp, width);
+ // store first part
+ chunks.add(tmp.substring(0, index));
+ // skip whitespace at beginning of line
+ while(index < tmp.length() && tmp.charAt(index) == ' ') {
+ index += 1;
+ }
+ // remove a newline
+ if(index < tmp.length() && tmp.regionMatches(index, NEWLINE, 0, NEWLINE.length())) {
+ index += NEWLINE.length();
+ }
+ if(index >= tmp.length()) {
+ break;
+ }
+ tmp = tmp.substring(index);
+ }
+
+ return chunks;
+ }
+
+ /**
+ * Returns a string with the specified number of whitespace.
+ *
+ * @param n the number of whitespace characters
+ * @return a string with the specified number of blanks
+ */
+ public static String whitespace(int n) {
+ if(n < WHITESPACE_BUFFER.length()) {
+ return WHITESPACE_BUFFER.substring(0, n);
+ }
+ char[] buf = new char[n];
+ for(int i = 0; i < n; i++) {
+ buf[i] = WHITESPACE_BUFFER.charAt(0);
+ }
+ return new String(buf);
+ }
+
+ /**
+ * Pad a string to a given length by adding whitespace to the right.
+ *
+ * @param o original string
+ * @param len destination length
+ * @return padded string of at least length len (and o otherwise)
+ */
+ public static String pad(String o, int len) {
+ if(o.length() >= len) {
+ return o;
+ }
+ return o + whitespace(len - o.length());
+ }
+
+ /**
+ * Pad a string to a given length by adding whitespace to the left.
+ *
+ * @param o original string
+ * @param len destination length
+ * @return padded string of at least length len (and o otherwise)
+ */
+ public static String padRightAligned(String o, int len) {
+ if(o.length() >= len) {
+ return o;
+ }
+ return whitespace(len - o.length()) + o;
+ }
+
+ /**
+ * Get the width of the terminal window (on Unix xterms), with a default of 78
+ * characters.
+ *
+ * @return Terminal width
+ */
+ public static int getConsoleWidth() {
+ int termwidth = 78;
+ try {
+ termwidth = Integer.parseInt(System.getenv("COLUMNS")) - 1;
+ }
+ catch(Exception e) {
+ // Do nothing, stick with default of 78.
+ }
+ return termwidth;
+ }
+
+ /**
+ * Formats a time delta in human readable format.
+ *
+ * @param time time delta in ms
+ * @return Formatted string
+ */
+ public static String formatTimeDelta(long time, CharSequence sep) {
+ final StringBuilder sb = new StringBuilder();
+ final Formatter fmt = new Formatter(sb);
+
+ for(int i = TIME_UNIT_SIZES.length - 1; i >= 0; --i) {
+ // We do not include ms if we are in the order of minutes.
+ if(i == 0 && sb.length() > 4) {
+ continue;
+ }
+ // Separator
+ if(sb.length() > 0) {
+ sb.append(sep);
+ }
+ final long acValue = time / TIME_UNIT_SIZES[i];
+ time = time % TIME_UNIT_SIZES[i];
+ if(!(acValue == 0 && sb.length() == 0)) {
+ fmt.format("%0" + TIME_UNIT_DIGITS[i] + "d%s", acValue, TIME_UNIT_NAMES[i]);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Formats the string array d with the specified separator.
+ *
+ * @param d the string array to be formatted
+ * @param sep the separator between the single values of the double array,
+ * e.g. ','
+ * @return a String representing the string array d
+ */
+ public static String format(String[] d, String sep) {
+ StringBuffer buffer = new StringBuffer();
+ for(int i = 0; i < d.length; i++) {
+ if(i > 0) {
+ buffer.append(sep).append(d[i]);
+ }
+ else {
+ buffer.append(d[i]);
+ }
+ }
+ return buffer.toString();
+ }
+} \ No newline at end of file