Aufgabe 1

Lösungsidee

Es wurde der auf http://www.diaware.de/html/roemzahl.html beschriebene Aufbau für die Lösung der Aufgabe genutzt. Im folgenden werden die auf dieser Webseite angeführten Punkte für Regeln und Aufbau darum ergänzt, wie sie im Prg. umgesetzt wurden.

  1. Die Grundeinheit eines römischen Zahlwortes soll als "römisches Ziffernzeichen" RZ bezeichnet werden. Ein römisches Zahlwort besteht hernach aus einer Aneinanderreihung von RZ.
    Beispielsweise: 'M', 'D', 'IX'
    Ein römisches Ziffernzeichen wurde im Prg. mit romanSign bezeichnet.
  2. Ein RZ ist entweder ein Grundzeichen GZ, ein Hilfszeichen HZ oder eine "subtraktive Kombination" SK.
    Somit besteht ein röm. Zeichen aus maximal 2 Grundzeichen. Dieser Umstand findet in der Methode intValue(String,boolean) Berücksichtigung. Die Werte der römischen Zeichen werden immer erst ausgewertet, wenn sichergestellt ist, dass es vollständig ist. D.h. bei nebeneinanderstehenden Grundzeichen (Bsp. 'IX') wird immer überprüft, ob sie "zs.gehören" (wie es bei 'IX' der Fall ist).
    Römische Grundzeichen wurden im Prg. mit basicRomanSign bezeichnet.
  3. Jedes RZ besitzt eine definierte Wertigkeit.
    Für Wertigkeit eines röm. Grundzeichens wurde eine eigene Klasse BasicRomanSign implementiert. Diese wird schließlich in RomanNumber für ein Array ROMAN_SIGN genutzt, in welcher alle Grundzeichen und deren Wertigkeit gespeichert werden. Dieses Array kann theoretisch (würde es mehr röm. Grundzeichen geben) erweitert werden, ohne das die Methoden des Prg. angepasst werden müssen.
  4. In einem römischen Zahlwort sind die einzelnen RZ mit absteigender Wertigkeit von links nach rechts sortiert angeordnet.
    Diese Regel wird entsprechend der Aufgabenstellung nur beim direkten Aufrufen der Methode intValue berücksichtigt, wenn tolerant = false übergeben wird. Da beim Konstruieren eines RomanNumber-Objekts die röm. Zahl "tolerant" interpretiert werden soll, wird im Konstruktor dieselbe Methode mit tolerant = true aufgerufen.
  5. Der Wert eines römischen Zahlwortes bestimmt sich aus der Summe der Wertigkeiten der einzelnen RZ.
    Die Summe von zwei römischen Zeichen wird erst berechnet, wenn im Falle von tolerant = false sichergestellt ist, dass die vorherige Bedingung (4.) erfüllt ist. Die Berechnung der Wertigkeit erfolgt in der Methode rating(char[],tolerant) (für subtraktive Kombinationen) bzw. mit rating(char) (für Grundzeichen)
  6. Ein RZ aus dem selben GZ darf höchstens 3 mal und aus dem selben HZ sowie aus der selben SK darf höchstens einmal erscheinen. Eine Ausnahme bildet die Zahl 4 (= IIII) auf Zifferblättern von Uhren.
    Auch die erste dieser Regeln wird berücksichtigt, nicht berücksichtigt werden mehrfach vorkommende HZ und SK (ist auch nicht in der Aufgabenstellung enthalten)
  7. Eine SK besteht aus 2 Zeichen, wobei ein GZ links von einem GZ oder HZ größerer Wertigkeit steht.
    Besondere Regel:
    I steht nur vor V und X
    X steht nur vor L und C
    C steht nur vor D und M
    Wie schon erwähnt, findet dieser Umstand in der Methode intValue(String,boolean) Berücksichtigung. Die besondere Regel wird in rating(char[],tolerant) berücksichtigt und zwar nur im Falle von tolerant = false.
  8. Die resultierende Wertigkeit einer SK ist die Differenz zwischen den Wertigkeiten der beiden enthaltenen GZ und/oder HZ.
    Die Wertigkeit von SK wird in rating(char[],tolerant) berechnet.
  9. Rechts neben einer SK dürfen nur RZ folgen, welche GZ und/oder HZ enthalten, die eine niedere Wertigkeit besitzen, als der linke Bestandteil der besagten SK.
    Diese Regel findet wiederum nur bei tolerant = false Berücksichtigung.

Das Programm wurde auch ausführlich im Source dokumentiert.

Source

/**
 * Softwareentwicklung I - Exercise 7/1.
 * Roman number.
 * It allows the creation of roman numbers on base of a roman number in a 
 * String or an integer value. 
 * The class also allows the transformation from roman number to int and 
 * reversed without creation of a RomanNumber object - 
 * method intValue(String,tolerant) and getRomanNumber(int).
 * In-source comments are followed by the described code.
 * 
 * @see http://www.diaware.de/html/roemzahl.html
 * @author Daniel Brunthaler (0255054)
 * @version 1.0
 */
public class RomanNumber {

    /**
     * Constant for roman numbers which are not valid.
     */
    public static final String NOT_VALID = "???";
    
    // This array contais all possible basic roman signs. It is initialized in 
    // the static initializer below. 
    private static final BasicRomanSign[] ROMAN_SIGN;
    
    static {
        // The possible signs can be extended ad libitum, but the last basic roman
        // sign always must be a 10 to the power of n. I know, this does not make 
        // really sense since there are no more basic roman signs, but who knows, 
        // what it is anytime good for ... :)
        ROMAN_SIGN = new BasicRomanSign[7];
        ROMAN_SIGN[0] = new BasicRomanSign('I',1);
        ROMAN_SIGN[1] = new BasicRomanSign('V',5);
        ROMAN_SIGN[2] = new BasicRomanSign('X',10);
        ROMAN_SIGN[3] = new BasicRomanSign('L',50);
        ROMAN_SIGN[4] = new BasicRomanSign('C',100);
        ROMAN_SIGN[5] = new BasicRomanSign('D',500);
        ROMAN_SIGN[6] = new BasicRomanSign('M',1000);
    }
    
    // The roman number in a String.
    private String romanNumber;
    
    // The integer value for this roman number.
    private int intValue;
    
    /**
     * Constructs a RomanNumber object.
     * @param intValue integer value which this roman number should stand for.
     */
    public RomanNumber(int intValue) {
        super();
        romanNumber = getRomanNumber(intValue);
        this.intValue = intValue;
    }
    
    /**
     * Constructs a RomanNumber object.
     * @param romanNumber roman number, this number is interpreted "tolerant",
     *          this means that certain rules are ignored. 
     */
    public RomanNumber(String romanNumber) {
        super();
        // Check roman number with tolerant rules.
        intValue = intValue(romanNumber,true);
        if (intValue < 0)
            this.romanNumber = null;
        else 
            this.romanNumber = romanNumber;
    }
    
    /**
     * Finds the basic roman sign for the given integer value.
     * @param intValue for which the basic roman sign should be found.
     * @return basic roman sign for the given integer value.
     */
    private static final String getBSR(int intValue) {
        // The ROMAN_SIGN array is scanned for the sought integer value.
        for (int i = 0;i < ROMAN_SIGN.length;i++)
            if (intValue == ROMAN_SIGN[i].getIntValue())
                return Character.toString(ROMAN_SIGN[i].getSign());
        return "?";
    }
    
    /**
     * The maximum integer value represented by a basic roman sign.
     * Depends on the containing of the ROMAN_SIGN array.
     * @return maximum integer value represented by a basic roman sign.
     */
    private static final int getMax() {
        int max = 0;
        // The ROMAN_SIGN array is scanned for the maximum integer value.
        for (int i = 0;i < ROMAN_SIGN.length;i++)
            if (ROMAN_SIGN[i].getIntValue() > max)
                max = ROMAN_SIGN[i].getIntValue();
        return max;
    }
        
    /**
     * Finds a roman number for a certain integer value.
     * @param intValue for which a roman number should be found.
     * @return a roman number representing the given integer value.
     */
    public static String getRomanNumber(int intValue) {
        String romanNumber = "", sign;
        int max = getMax();
        int div = max;
        int digit, i;
        if (intValue >= max * 4 || intValue <= 0)
            // the given integer value is bigger than the maximum presentable 
            // roman number
            return NOT_VALID;
        while (div >= 1) {
            // digit for digit of the integer number is analysed.
            // for example 1995: 1995 / 1000 = 1,995 absolute = 1 => 'M'
            // (1995 - 1000) / 100 = 9,95 absolute = 9 => 'M' + 'CM'
            // (995 - 900) / 10 = 9,5 absoulte = 9 => 'MCM' + 'XC'
            // (95 - 90) / 1 = 5 absolute = 5 => 'MCMXC' + 'V'
            digit = Math.abs(intValue / div);
            if (digit == 0) {
            } else if (digit <= 3) {
                sign = getBSR(div);
                for (i = 0;i < digit;i++)
                    romanNumber += sign;
            } else if (digit == 4) {
                romanNumber += getBSR(div) + getBSR(div * 5);
            } else if (digit == 5) {
                romanNumber += getBSR(div * 5);
            } else if (digit <= 8) {
                romanNumber += getBSR(div * 5);
                sign = getBSR(div);
                for (i = 0;i < digit - 5;i++)
                    romanNumber += sign;
            } else if (digit == 9) {
                romanNumber += getBSR(div) + getBSR(div * 10);
            }
            intValue -= div * digit;
            div /= 10;
        }
        return romanNumber;
    }
    
    /**
     * Finds the integer value of the given roman number.
     * The method allows a "tolerant" analyse of the roman number, if tolerant
     * is set to true.
     * @param romanNumber which should be analysed. 
     * @param tolerant analyse of the roman number. Certain rules for roman
     *           numbers are ignored, if this is set to true.
     * @return integer value which represents the given roman number.
     *              The function returns a negative integer, if the given 
     *              roman number is not valid.
     */
    public static int intValue(String romanNumber, boolean tolerant) {
        int rnLength = romanNumber.length();    // length of the roman number
        int intValue = 0;                       // int value of the roman number
        int bsCounter = 1;  // Counter for basic roman signs, if it counts the 
                      // same sign more than three times => invalid roman number
        char basicRomanSign = ' '; // certain basic sign out of the roman number
        char lastBasicSign = ' ';  // last analysed basic roman sign
        char[] romanSign = {' ',' '};       // roman sign
        char[] lastRomanSign = {' ',' '};   // last roman sign (for checking
                                            //  if signs are in ascending order)
        int ratingBRS, ratingLBS, ratingRS, ratingLRS;
        if (rnLength < 1) {
            return -1;
        } else if (rnLength == 1) {
            // roman number contains only one sign => return rating of this sign
            return rating(romanNumber.charAt(0));
        } else if (rnLength > 1) {
            basicRomanSign = romanNumber.charAt(0);
            ratingBRS = rating(basicRomanSign);
            if (ratingBRS < 0)
                return -1;
            else {
                romanSign[0] = basicRomanSign;
                lastBasicSign = basicRomanSign;
            }
        }
        ratingLBS = rating(lastBasicSign);
        ratingLRS = rating(lastRomanSign,tolerant);
        for (int i = 1;i < rnLength;i++) {
            // check sign for sign from given number
            basicRomanSign = romanNumber.charAt(i);
            if (basicRomanSign == lastBasicSign)
                bsCounter++;
            else 
                bsCounter = 1;
            if (bsCounter > 3) 
                return -1;
            ratingBRS = rating(basicRomanSign);
            if (ratingBRS < 0)  // basic roman sign does not exist.
                return -1;
            if (romanSign[1] == ' ' && ratingBRS > ratingLBS) {
                // subtractive combination (ex. 'IX')
                romanSign[1] = basicRomanSign;
            } else {
                // find out rating of roman sign, could be a subtractive
                // combination like 'IX' 
                ratingRS = rating(romanSign,tolerant);
                if (ratingRS < 0) 
                    return -1;
                if (tolerant || ratingLRS == 0 || ratingLRS >= ratingRS)
                    // check (if tolerant = false) if rating of last roman 
                    // sign is greater than rating of following roman sign
                    // only if there is a last roman sign (!= 0)
                    intValue += ratingLRS;
                else
                    return -1;
                lastRomanSign[0] = romanSign[0];
                lastRomanSign[1] = romanSign[1];
                romanSign[0] = basicRomanSign;
                romanSign[1] = ' ';
            }
            lastBasicSign = basicRomanSign;
            ratingLBS = rating(lastBasicSign);
            ratingLRS = rating(lastRomanSign,tolerant);
        }
        ratingRS = rating(romanSign,tolerant);
        // if loop is exited, last analysed roman signs have to be considered
        // in calculation
        if (ratingRS < 0) 
            return -1;
        if (tolerant || ratingLRS == 0 || ratingLRS >= ratingRS)
            intValue += ratingLRS + ratingRS;
        else
            return -1;
        return intValue;
    }
    
    /**
     * Rating or integer value of a basic roman sign, for example 'V' = 5.
     * @param basicRomanSign for which the integer value should be returned.
     * @return integer value for a certain basic roman sign.
     */
    private static final int rating(char basicRomanSign) {
        if (basicRomanSign == ' ')
            return 0;
        else 
            // scan the ROMAN_SIGN array for the given basic roman sign
            for (int i = 0;i < ROMAN_SIGN.length;i++)
                if (ROMAN_SIGN[i].getSign() == basicRomanSign)
                    return ROMAN_SIGN[i].getIntValue();
            return -1;
    }
    
    /**
     * Rating or integer value of roman signs, like 'IX' (subtractive 
     * combination). If the roman sign only contains a basic roman sign, the
     * function calls the function rating(char).
     * The paramter tolerant gives the option to ignore the rule
     * 'I' only stands before 'V' or 'X', 'X' only stands before 'L' or 'C' and
     * 'C' only stands before 'D' or 'M'.
     * @param romanSign which should be analysed.
     * @param tolerant if true, the described rule is ignored.
     * @return integer value for this roman sign. 
     */
    private static final int rating(char[] romanSign, boolean tolerant) {
        if (romanSign.length == 0 || romanSign.length > 2) {
            return -1;
        } else if (romanSign[1] == ' ') {
            // roman sign contains only one sign 
            // => find out rating of this sign.
            return rating(romanSign[0]);
        } else {
            int ratingLeft = rating(romanSign[0]);
            int ratingRight = rating(romanSign[1]);
            // the rating of the left basic sign in a roman sign is greater
            // than the right basic sign => roman sign is invalid.
            if (ratingLeft > ratingRight) 
            // the rating of the right basic roman sign is greater than the
            // rating of the left basic roman sign * 10 (like 'IC' or 'XM').
            // this rule is ignored, if tolerant is true.
                return -1;
            if (!tolerant && ratingRight > ratingLeft * 10) 
                return -1;
            if (!tolerant && Integer.toString(ratingLeft).charAt(0) == '5')
                // The left basic roman sign is euqal 5 * 10^n => roman sign
                // is invalid.
                // this rule is ignored, if tolerant is true.
                return -1;
            return ratingRight - ratingLeft;
        }
    }
    
    /**
     * Returns the integer value of this roman number object.
     * @return the integer value of this roman number object.
     */
    public int intValue() {
        if (intValue < 0)
            return 0;
        else
            return intValue;
    }
    
    /**
     * Returns the roman number as a String. 
     * @return the roman number as a String.
     */
    public String toString() {
        if (romanNumber == null) 
            return NOT_VALID;
        else 
            return romanNumber;
    }
    
    /**
     * For testing purpose only.
     * @param args no arguments have to be given.
     */
    public static void main(String[] args) {
        // Test of method RomanNumber.intValue(String,boolean)
        IO.writeLn("intValue(\"\"),false) = " + 
                RomanNumber.intValue("",false));
        IO.writeLn("intValue(\"X\"),false) = " + 
                RomanNumber.intValue("X",false));
        IO.writeLn("intValue(\"CCC\"),false) = " + 
                RomanNumber.intValue("CCC",false));
        IO.writeLn("intValue(\"IX\"),false) = " + 
                RomanNumber.intValue("IX",false));
        IO.writeLn("intValue(\"XIX\"),false) = " + 
                RomanNumber.intValue("XIX",false));                
        IO.writeLn("intValue(\"IXX\"),false) = " + 
                RomanNumber.intValue("IXX",false));
        IO.writeLn("intValue(\"CMXCIX\"),false) = " + 
                RomanNumber.intValue("CMXCIX",false));
        IO.writeLn("intValue(\"IM\"),false) = " + 
                RomanNumber.intValue("IM",false));
        
        // Test of creation a RomanNumber object with a String.
        IO.writeLn("(new RomanNumber(\"\")).intValue() = " + 
                (new RomanNumber("")).intValue());
        IO.writeLn("(new RomanNumber(\"X\")).intValue() = " + 
                (new RomanNumber("X")).intValue());
        IO.writeLn("(new RomanNumber(\"CCC\")).intValue() = " + 
                (new RomanNumber("CCC")).intValue());
        IO.writeLn("(new RomanNumber(\"IX\")).intValue() = " + 
                (new RomanNumber("IX")).intValue());
        IO.writeLn("(new RomanNumber(\"XIX\")).intValue() = " + 
                (new RomanNumber("XIX")).intValue());
        IO.writeLn("(new RomanNumber(\"IXX\")).intValue() = " + 
                (new RomanNumber("IXX")).intValue());
        IO.writeLn("(new RomanNumber(\"IXX\")).toString() = " + 
                (new RomanNumber("IXX")).toString());
        IO.writeLn("(new RomanNumber(\"CMXCIX\")).intValue() = " + 
                (new RomanNumber("CMXCIX")).intValue());
        IO.writeLn("(new RomanNumber(\"IM\")).intValue() = " + 
                (new RomanNumber("IM")).intValue());
                
        // Test of RomanNumber.getRomanNumber(int)
        IO.writeLn("getRomanNumber(-5)" + RomanNumber.getRomanNumber(-5));
        IO.writeLn("getRomanNumber(0)" + RomanNumber.getRomanNumber(0));
        IO.writeLn("getRomanNumber(1)" + RomanNumber.getRomanNumber(1));
        IO.writeLn("getRomanNumber(3)" + RomanNumber.getRomanNumber(3));
        IO.writeLn("getRomanNumber(5)" + RomanNumber.getRomanNumber(5));
        IO.writeLn("getRomanNumber(8)" + RomanNumber.getRomanNumber(8));
        IO.writeLn("getRomanNumber(9)" + RomanNumber.getRomanNumber(9));
        IO.writeLn("getRomanNumber(89)" + RomanNumber.getRomanNumber(89));
        IO.writeLn("getRomanNumber(99)" + RomanNumber.getRomanNumber(99));
        IO.writeLn("getRomanNumber(459)" + RomanNumber.getRomanNumber(459));
        IO.writeLn("getRomanNumber(1381)" + RomanNumber.getRomanNumber(1381));
        IO.writeLn("getRomanNumber(3999)" + RomanNumber.getRomanNumber(3999));
        IO.writeLn("getRomanNumber(9111)" + RomanNumber.getRomanNumber(9111));
        
        // Test of creation a RomanNumber object with an integer value.
        IO.writeLn("(new RomanNumber(-5)).toString() = " + 
                (new RomanNumber(-5)).toString());
        IO.writeLn("(new RomanNumber(0)).toString() = " + 
                (new RomanNumber(0)).toString());
        IO.writeLn("(new RomanNumber(1)).toString() = " +
                (new RomanNumber(1)).toString());
        IO.writeLn("(new RomanNumber(3)).toString() = " +
                (new RomanNumber(3)).toString());
        IO.writeLn("(new RomanNumber(5)).toString() = " +
                (new RomanNumber(5)).toString());
        IO.writeLn("(new RomanNumber(8)).toString() = " +
                (new RomanNumber(8)).toString());
        IO.writeLn("(new RomanNumber(9)).toString() = " +
                (new RomanNumber(9)).toString());
        IO.writeLn("(new RomanNumber(89)).toString() = " +
                (new RomanNumber(89)).toString());
        IO.writeLn("(new RomanNumber(459)).toString() = " +
                (new RomanNumber(459)).toString());
        IO.writeLn("(new RomanNumber(1381)).toString() = " +
                (new RomanNumber(1381)).toString());                
        IO.writeLn("(new RomanNumber(3999)).toString() = " +
                (new RomanNumber(3999)).toString());
        IO.writeLn("(new RomanNumber(9111)).toString() = " + 
                (new RomanNumber(9111)).toString());
        System.exit(0);
    }
}

/**
 * Softwareentwicklung I - Exercise 7/1.
 * Basic roman sign for roman numbers.
 * In-source comments are followed by the described code.
 * 
 * @see RomanNumber
 * @author Daniel Brunthaler (0255054)
 * @version 1.0
 */
class BasicRomanSign {
    
    private char basicRomanSign;
    private int intValue;
    
    /**
     * Constructor for a basic roman sign.
     * @param basicRomanSign which should be created.
     * @param intValue of the basic roman sign.
     */
    BasicRomanSign(char basicRomanSign, int intValue) {
        this.basicRomanSign = basicRomanSign;
        this.intValue = intValue;
    }
    
    /**
     * Basic roman sign.
     * @return basic roman sign.
     */
    char getSign() {
		return basicRomanSign;
	}

    /**
     * Integer value of this basic roman sign.
     * @return integer value of this basic roman sign.
     */
	int getIntValue() {
		return intValue;
	}

}

  

Test

Es wurden in der main-Methode möglichst viele verschiedenartige Testfälle implementiert. Alle diese Testfälle hier mit Zweck und erwarteter Ausgabe aufzulisten, erscheint mir nicht zielführend. Die Ausgabe wurde in eine Datei umgeleitet und ist im folgenden angedruckt.

intValue(""),false) = -1
intValue("X"),false) = 10
intValue("CCC"),false) = 300
intValue("IX"),false) = 9
intValue("XIX"),false) = 19
intValue("IXX"),false) = -1
intValue("CMXCIX"),false) = 999
intValue("IM"),false) = -1
(new RomanNumber("")).intValue() = 0
(new RomanNumber("X")).intValue() = 10
(new RomanNumber("CCC")).intValue() = 300
(new RomanNumber("IX")).intValue() = 9
(new RomanNumber("XIX")).intValue() = 19
(new RomanNumber("IXX")).intValue() = 19
(new RomanNumber("IXX")).toString() = IXX
(new RomanNumber("CMXCIX")).intValue() = 999
(new RomanNumber("IM")).intValue() = 999
getRomanNumber(-5)???
getRomanNumber(0)???
getRomanNumber(1)I
getRomanNumber(3)III
getRomanNumber(5)V
getRomanNumber(8)VIII
getRomanNumber(9)IX
getRomanNumber(89)LXXXIX
getRomanNumber(99)XCIX
getRomanNumber(459)CDLIX
getRomanNumber(1381)MCCCLXXXI
getRomanNumber(3999)MMMCMXCIX
getRomanNumber(9111)???
(new RomanNumber(-5)).toString() = ???
(new RomanNumber(0)).toString() = ???
(new RomanNumber(1)).toString() = I
(new RomanNumber(3)).toString() = III
(new RomanNumber(5)).toString() = V
(new RomanNumber(8)).toString() = VIII
(new RomanNumber(9)).toString() = IX
(new RomanNumber(89)).toString() = LXXXIX
(new RomanNumber(459)).toString() = CDLIX
(new RomanNumber(1381)).toString() = MCCCLXXXI
(new RomanNumber(3999)).toString() = MMMCMXCIX
(new RomanNumber(9111)).toString() = ???

Aufgabe 2

Lösungsidee

Das Prg. wurde ausschließlich in der main-Methode implementiert. Mit Hilfe der in der Aufgabenstellung angeg. Klassen und Methoden fällt das Prg. verhältnismäßig klein aus. Der Text aus der Datei wird Zeichen für Zeichen analysiert, bei Leerzeichen wird überprüft, ob das Wort in der Zeile noch Platz findet (mit Hilfe eines "Spalten-Zeigers"), wenn nicht wird es in die nächste Zeile geschrieben. Außerdem wird bei jedem neuen Zeichen überprüft, ob das Wort als Ganzes noch in der Zeile Platz findet, ansonsten wird ein Teil des Wortes in eine ganze Zeile geschrieben.

Source

import IO.*;
/**
 * Softwareentwicklung I - Exercise 7/2.
 * Text formatter.
 * Outputs formated text read out from a given file with given number of
 * columns.
 * In-source comments are followed by the described code.
 * 
 * @author Daniel Brunthaler (0255054)
 * @version 1.0
 */
public class TextFormatter {
    
    /**
     * Constructor for TextFormatter.
     */
    public TextFormatter() {
        super();
    }
    
    /**
     * Formats given file with given number of columns. Ouputs the result in 
     * System.out.
     * @param args  
     */
    public static void main(String[] args) {
        int columns = 0;
        String infoColumn = "01234567890123456789012345678901234567890123456789012345678901234567890";
        String infoColumn2 = "0         10        20        30        40        50        60        70";
        String errMsgInsuffArgs = "Zu wenig Argumente angegeben!";
        String errMsgColumns = "Argument  ungültig!";
        String errMsgFile = "Datei nicht gefunden oder Lesefehler!";
        String infoSyntax = "TextFormatter  ";
        if (args.length < 2) {
            IO.writeLn(errMsgInsuffArgs);
            IO.writeLn(infoSyntax);
            System.exit(0);
        }
        try {
            columns = Integer.parseInt(args[1]);
        } catch (NumberFormatException e) {
            IO.writeLn(errMsgColumns);
            IO.writeLn(infoSyntax);
            System.exit(0);
        }
        try {
            String word = "";
            // open file.
            Infile in = new Infile(args[0]);
            IO.writeLn(infoColumn + "\n" + infoColumn2 + "\n");
            int column = 0;
            char ch = in.read();
            while (ch != IO.EOF) {
                // analyse char for char until end of file.
                if (ch == ' ') {
                    if (column + word.length() <= columns) {
                        // word finds place in actual line.
                        if (column != 0)
                            IO.write(" ");
                    } else {
                        // word finds no place in actual line => next line.
                        IO.writeLn();
                        column = 0;
                    }
                    column += word.length() + 1;
                    IO.write(word);
                    word = "";
                } else if (ch == '\n') {
                    // line feed in file, check if actual word finds place in 
                    // actual line or not.
                    if (column + word.length() > columns) 
                        IO.writeLn();
                    else 
                        IO.write(" ");
                    IO.writeLn(word);
                    word = "";
                    column = 0;
                } else {
                    // check if length of word is greater than columns of line.
                    if (word.length() + 1 > columns) {
                        IO.write("\n" + word + "\n");
                        column = 0;
                        word = "";
                    }
                    word += Character.toString(ch);
                }
                ch = in.read();
            }
            in.close();
        } catch (Exception e) {
            // error on file operation.
            IO.writeLn(errMsgFile);
            IO.writeLn(infoSyntax);
        }
    }
}

  

Test

Zum Testen wurde der in der Aufgabenstellung angeg. Beispieltext herangezogen. Die Ausgaben des Prg. TextFormatter wurden in eine Datei umgeleitet. Im Folgenden die Textdatei, sowie anschließend die Ausgaben des Prg. bei 70, 30 und 5 Zeichen pro Zeile.

Testdatei

Es war einmal ein kleines, süßes Mädchen, das immer ein Käppchen aus rotem Samt trug. Aufgrund dieses Attributes erhielt es ein Assign unter dem symbolischen Namen Rotkäppchen.
Eines Tages sprach die Mutter: "Rotkäppchen, die Gesundheit deiner Großmutter hat einen Interrupt bekommen. Wir müssen ein Pflegeprogramm entwickeln und zur Großmutter bringen, um das Problem zu lösen.
Verirre Dich jedoch nicht im Wald der alten Sprachen, sondern gehe nur ... 

70 Zeichen pro Zeile

01234567890123456789012345678901234567890123456789012345678901234567890
0         10        20        30        40        50        60        70

Es war einmal ein kleines, süßes Mädchen, das immer ein Käppchen aus
rotem Samt trug. Aufgrund dieses Attributes erhielt es ein Assign
unter dem symbolischen Namen Rotkäppchen.
Eines Tages sprach die Mutter: "Rotkäppchen, die Gesundheit deiner
Großmutter hat einen Interrupt bekommen. Wir müssen ein Pflegeprogramm
entwickeln und zur Großmutter bringen, um das Problem zu lösen.
Verirre Dich jedoch nicht im Wald der alten Sprachen, sondern gehe nur
...  

30 Zeichen pro Zeile

01234567890123456789012345678901234567890123456789012345678901234567890
0         10        20        30        40        50        60        70

Es war einmal ein kleines,
süßes Mädchen, das immer ein
Käppchen aus rotem Samt trug.
Aufgrund dieses Attributes
erhielt es ein Assign unter
dem symbolischen Namen
Rotkäppchen.
Eines Tages sprach die Mutter:
"Rotkäppchen, die Gesundheit
deiner Großmutter hat einen
Interrupt bekommen. Wir müssen
ein Pflegeprogramm entwickeln
und zur Großmutter bringen, um
das Problem zu lösen.
Verirre Dich jedoch nicht im
Wald der alten Sprachen,
sondern gehe nur ...  

5 Zeichen pro Zeile

01234567890123456789012345678901234567890123456789012345678901234567890
0         10        20        30        40        50        60        70

Es
war
einma
l ein
klein
es,
süßes
Mädch
en,
das
immer
ein
Käppc
hen
aus
rotem
Samt
trug.
Aufgr
und
...