package tio; import java.io.*; import java.text.*; /** * The class FormattedWriter contains * methods that allow for formatted printing. * It includes support for setting the width of the * output field, using left or right justification in * the output field, using an arbitrary fill * character, and setting the number of digits to the * right of the decimal point in floating point * values. * * @author C. E. McDowell * @version 1.2 corrected problem with floats with exponents. */ public class FormattedWriter extends PrintWriter { // constants for specifying justification public static final int LEFT = 1; public static final int RIGHT = 2; /** * Constructs a FormattedWriter object for an * OutputStream. * * @param os the OutputStream to write to */ public FormattedWriter(OutputStream os) { super(os, true); // make default auto-flushing } /** * Constructs a FormattedWriter object for a * FileWriter. * * @param writer the FileWriter to write to */ public FormattedWriter(FileWriter writer) { super(writer, true); } /** * Constructs a FormattedWriter object for writing * to a file. * * @param filename the name of the file to write to */ public FormattedWriter(String filename) throws java.io.IOException { this(new FileWriter(filename)); } /** * Set the output field width. If the value being * printed is less than the width of the field, then * the field will be padded with the pad character * (see setPadChar()). The field can be either left * or right justified (see setJustify()). * * @param width the width of the output field */ public void setWidth(int width) { if (width < 0) this.width = 0; else if (width > MAX_WIDTH) this.width = MAX_WIDTH; else this.width = width; } /** * Set the number of digits to be printed to the * right of the decimal point in floating point * values. * * @param places the number of places to the right * of the decimal point */ public void setDigits(int places) { decimalPlaces = places; form.setMaximumFractionDigits(decimalPlaces); } /** * Set the justification to be LEFT or RIGHT. * * @param leftOrRight use FormattedWriter.LEFT * or FormattedWriter.RIGHT * @exception IllegalArgumentException if not LEFT * or RIGHT */ public void setJustify(int leftOrRight) { if (leftOrRight != LEFT && leftOrRight != RIGHT) throw new IllegalArgumentException( "use FormattedWriter.LEFT or" + " FormattedWriter.RIGHT"); justify = leftOrRight; } /** * Set the character to be used in padding. * The default padding character is a blank. * * @param pad the character to use in padding */ public void setPadChar(char pad) { if (pad == ' ') padding = spaces; else if (pad == '0') padding = zeros; else padding = buildPadding(MAX_WIDTH, pad); } /** * Print a String in a field of the current * width using the current padding character * and justification. * * @param s the String to print */ public void printf(String s) { if (s.length() >= width) super.print(s); else if (justify == LEFT) super.print(s + padding.substring(0, width - s.length())); else super.print( padding.substring(0, width - s.length()) + s); } /** * Print a boolean in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(boolean value) { printf(String.valueOf(value)); } /** * Print a char in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(char value) { printf(String.valueOf(value)); } /** * Print an array of characters in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(char[] value) { printf(String.valueOf(value)); } /** * Print an int in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(int value) { printf(String.valueOf(value)); } /** * Print a long in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(long value) { printf(String.valueOf(value)); } /** * Print any Object in a field of the current * width, using the current padding character and justification. * * @param value the value to print */ public void printf(Object value) { printf(value.toString()); } /** * Print a double in a field of the current * width, with the current number of digits to the * right of the decimal point and using the current * padding character and justification. * * @param value the value to print */ public void printf(double value) { printf(trimDigits(String.valueOf(value))); } /** * Print a float in a field of the current * width, with the current number of digits to the * right of the decimal point and using the current * padding character and justification. * * @param value the value to print */ public void printf(float value) { printf(trimDigits(String.valueOf(value))); } /** * Same as printf() with a newline added at the end. */ public void printfln(String s) { printf(s); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(boolean value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(char value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(char[] value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(int value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(long value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(Object value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(double value) { printf(value); println(); } /** * Same as printf() with a newline added at the end. */ public void printfln(float value) { printf(value); println(); } /* * Trim the number of digits to the right of the * decimal point if there is one. */ private String trimDigits(String value) { int places; if (decimalPlaces == -1) return value; int pos = value.indexOf("."); int exp = value.indexOf("E"); if (exp == -1) places = value.length() - pos - 1; else places = exp - pos - 1; if (places <= decimalPlaces) return value; if (exp == -1) return round(value); else { String needsRounding = value.substring(0, exp); return round(needsRounding) + value.substring(exp); } } /* * Round the last digit of s. E.g. 1.2345 would be * returned as 1.235 and 1.234 would be returned as * 1.23. * This is done using a java.text.NumberFormat * object that had its decimal places set in * setDigits() above. */ private String round(String s) { // form is a java.text.NumberFormat object return form.format(Double.parseDouble(s)); } /* * Create an array of pad characters used for * quickly building strings of pad characters * by a call to substring (see printfln(String s)) */ private static String buildPadding(int width, char pad) { StringBuffer sbuf = new StringBuffer(width); for (int i = 0; i < width; ++i) sbuf.append(pad); return sbuf.toString(); } private static int MAX_WIDTH = 40; private static final String spaces = buildPadding(MAX_WIDTH, ' '); private static final String zeros = buildPadding(MAX_WIDTH, '0'); private String padding = spaces; private int width = 0; private int justify = LEFT; // -1 means use max precision private int decimalPlaces = -1; // used in trimming decimal digits private NumberFormat form = NumberFormat.getInstance(); }