import java.io.*; import java.util.StringTokenizer; /* Justify: uses one command line argument, "width-of-line" and then reads from standard input until a line with only "XXXX" is encountered or end of file. If there is another command line argument, a file name then it reads from a file. It creates one object of class FormatWriter to produce right and left justified text which is of width, "width-of-line". */ class Justify { public static void main (String[] args) throws IOException { final String usageMessage = "Usage: java Justify width [file|stdin]\nwidth > 0 is a command line argument\nfile is an optional second command line argument,\notherwise it reads from stdin."; int width = 0; DataInputStream in; try { // Normal flow of control. if (args.length > 0) width = Integer.parseInt(args[0]); else { System.err.println(usageMessage); System.exit(0); } if (width <= 0 ) { System.err.println(usageMessage); System.exit(0); } if (args.length > 1) { FileInputStream fin = new FileInputStream(args[1]); in = new DataInputStream(fin); } else in = new DataInputStream(System.in); FormatWriter out = new FormatWriter (width); String line; do line=in.readLine(); while (out.writeLine(line)); } // Catch exceptional circumstances. catch (NegativeArraySizeException e) { // Handled above, never executed. System.err.println(usageMessage); } catch (NumberFormatException e) { // Width argument is not an integer. System.err.println(usageMessage); } catch (FileNotFoundException e) { // Optional file argument not found. System.err.println(usageMessage); } finally { // Possibly for future use. } } } /* FormatWriter does the work of formating - with the help of FormatLine - and printing lines of the required width. Specifically it prints lines that are complete but stores lines that are partially complete. It knows a line is complete if adding the next word overflows the line or when a paragraph ends or when a line with only "XXXX" is encountered. A paragraph is denoted by an empty line or a line with only spaces. The final line is printed when it receives the "XXXX". After printing "storedLine" FormatWriter resets "storedLine" to empty. */ class FormatWriter { static final String STOPPER = "XXXX"; private static final String blank = " "; private String storedLine = ""; private int width; private FormatLine format; FormatWriter (int width) { format = new FormatLine(width); this.width = width; } /* writeLine: Writes only completely formated lines, partial lines are stored until more lines are read or null is sent or a paragraph end is reached. A paragraph is recognized as an empty string or a line containing only white space. After printing a line FormatWriter resets the storedLine to empty. @return false when "XXXX" is read otherwise returns true. */ public boolean writeLine (String line) { if (line == null || line.equals(STOPPER)) { // end of file so print any remaining line and exit System.out.println (storedLine.trim()); storedLine = ""; return false; } line = line.trim(); if (line.length() == 0) { // blank line indicating a paragraph if (storedLine.trim().length() != 0) System.out.println(storedLine.trim() + "\n"); // The above 'if' has the effect of ignoring multiple lines between paragraphs. // Uncomment the following 'else' you want to keep multiple lines. // else System.out.println(); storedLine = ""; return true; } StringTokenizer token = new StringTokenizer(line); StringBuffer lineBuffer = new StringBuffer(width); lineBuffer.append(storedLine); while (token.hasMoreTokens()) { String word = token.nextToken(); if (lineBuffer.length() + word.length() > width) { // print only when adding another word will make the line too wide System.out.println(format.rightAndLeftJustify(lineBuffer.toString())); lineBuffer = new StringBuffer(width); } lineBuffer.append(word).append(blank); } storedLine = lineBuffer.toString(); return true; } } /* FormatLine constructor sets up its width. Method rightAndLeftJustify takes one line and right and left justifies it. */ class FormatLine { private boolean padLeft = true; private static final String blank = " "; private int width; FormatLine (int width) { this.width = width; } public String rightAndLeftJustify (String line) { line = line.trim(); StringTokenizer token = new StringTokenizer(line); if (line.length() >= width || token.countTokens() <= 1) { // This is a redundant condition when called from FormatWriter.writeLine. // If at most one word then return it. return line; } StringBuffer lineBuffer = new StringBuffer(width); int spaces = token.countTokens() - 1; int blanksToAdd = width - line.length() + spaces; int blanksPerSpace = blanksToAdd / spaces; int blanksRemaining = blanksToAdd % spaces; StringBuffer interWordSpace = new StringBuffer(blanksPerSpace); for (int i=0;i 0 || ! padLeft && blanksRemaining >= token.countTokens()) { // Add remainder of blanks to the left or right end of the line. lineBuffer.append(blank); blanksRemaining--; } } padLeft = ! padLeft; // Alternate adding remainder of blanks from left or right. return lineBuffer.toString(); } }