// Autor: Martin Heinrich // MatNr: 0125222 // Klasse zu BspNr: 3061 // Dient dazu einen Text zu überprüfen und zu bearbeiten. // Die Klasse Strings enthält die in den Spezifikationen festgelegten Regeln. // Die Dokumentation befindet sich in der Datei Texte.txt // Die Bezeichnungen //[Ziffer][Buchstabe] beziehen sich auf die Dokumentation (Texte.txt) public class Strings { private static final String lLetters = "enaiourbcdfghjklmpqstvwzxy"; // Ich habe die Häufigkeiten nicht nachgeschlagen private static final String uLetters = "ENAIOURBCDFGHJKLMPQSTVWZXY"; // ...aber vielleicht bringts ein paar ns :-) private static final String Letters = "enaiourbcdfghjklmpqstvwzxyAEIOUNRBCDFGHJKLMPQSTVWZXY"; private static final char Space = ' '; private static final char LineBreak = '-'; private static final String NewLine = "\n"; private static final String MetaChars = ",;.\"() "; // Außer Buchstaben erlaubte Zeichen private static final String Simplify = ",;.\""; // Zeichen, die nur einmal ausgegeben werden sollen private static final String CommaSemiDot = ".,;"; private static final String[] BreakBefore = {"keit", "heit", "los", "sam", "schaft"}; private static final String[] BreakBehind = {"keit", "heit", "los", "sam"}; // Die MindestAnzahl an Buchstaben (=2) bringt so viele Vorteile, dass sie an mehreren Stellen einfließt :-( private static final int maxLetterCount = 12; private static String text; // enthält den gesamten eingegebenen Text // wordCount wird erst durch checkSpecifications (eigentl. checkWords) ermittelt: private static int wordCount = -1; // enthält die Anzahl der Wörter //3a // text, word- und breakCount können nur gelesen werden: public static String getString() {return new String(text);} // erstellt ein NEUES Objekt public static StringBuffer getStringBuffer() {return new StringBuffer(text);} // "wordCount" wird erst durch checkSpecifications (eigentl. checkWords) ermittelt! public static int getWordCount() {return wordCount;} // "breakCount" wird immer neu berechnet: gibt die Anzahl der Abteilungszeichen zurück (-): public static int getBreakCount() { int count = 0, cIndex = -1; while (-1 != (cIndex = text.indexOf(LineBreak, cIndex+1))) {count++;}; return count; } // getBreakCount //3b // Constructors: Strings() {text = new String();} Strings(String initText) {text = (new String(initText)).trim();} // erzeugt auf alle Fälle ein NEUES Objekt Strings(StringBuffer initText) {text = (new String(initText)).trim();} //**************************************************************** // append: fügt einen String oder StringBuffer an // insSpace (optional [default = (text != "")]): fügt ein Leerzeichen zwischen den Stings ein wenn true public static void append(String appText) {append(appText, text.length() != 0);} public static void append(StringBuffer appText) {append(appText, text.length() != 0);} public static void append(String appText, boolean insSpace) { if (insSpace) {text += Space;}; text += appText.trim(); } // append(String appText, boolean insSpace) public static void append(StringBuffer appText, boolean insSpace) { if (insSpace) {text += Space;}; text += appText.toString().trim(); } // append(StringBuffer appText, boolean insSpace) //**************************************************************** //4a //**************************************************************** // checkSpecifications: überprüft alle Korrektheitsregeln und korrigiert Interpunktionsfehler public static boolean checkSpecifications() { return ( // Die Methode ruft nur die entsprechenden privaten Methoden auf: checkChars() && findErrors() && checkWords() ); // return } // checkSpecifications //**************************************************************** //**************************************************************** // forceLines: führt alle Zeilenumbrüche durch // width: gibt die Zeilenbreite an // ACHTUNG: Wenn die Methode abbricht (d.h. return false), ist text zerstört!!! public static boolean forceLines(int width) { //5a String tText = text; // von hier wird der alte String gelesen; tText wird "abgebaut" int Index; // Zeigt die aktuelle Möglichkeit den String abzuteilen (jeweils vor Index) //5b // Die folgenden Variablen werden nur beim Suchen nach Abteilungsmöglichkeiten NACH Silben eingesetzt String lText; // Übernimmt den String in Kleinbuchstaben, damit die Silbensuche ohne Unterscheidung verläuft int tIndex; // Wird zum Vergleichen mit Index verwendet text = new String(); // Der umgebrochene Text wird neu aufgebaut... //5c while (tText.length() > width) { //5d Index = tText.lastIndexOf(',', width-1)+1; // NACH einem Komma darf abgeteilt werden Index = Math.max(Index, tText.lastIndexOf(Space, width)); // VOR einem Leerzeichen darf abgeteilt werden // Wenn ich VOR einer Silbe abteilen will, besteht diese sowieso nur aus Kleinbuchstaben! for (int i = 0; i < BreakBefore.length; i++) { Index = Math.max(Index, tText.lastIndexOf(BreakBefore[i], width-1)); // VOR einer solchen Silbe }; // for (i) // '-' nicht vergessen //5e // Wenn ich NACH einer Silbe abteilen will, müssen noch zwei Buchstaben folgen lText = tText.substring(0, width-1).toLowerCase(); // so muss nicht alles (mehrfach) umgewandelt werden for (int i = 0; i < BreakBehind.length; i++) { tIndex = lText.lastIndexOf(BreakBehind[i]); if (tIndex != -1) { tIndex += BreakBehind[i].length(); try { // Wenn im Folgenden die Indexgrenze überschritten wird, gibt es definitiv keine 2 Buchstaben nach der Silbe if ((tIndex > Index) && (MetaChars.indexOf(tText.charAt(tIndex)) == -1) && (MetaChars.indexOf(tText.charAt(tIndex+1)) == -1)) { Index = tIndex;}; } catch (Exception e) {}; }; // if (tIndex) }; // for (i) //5f if (Index <= 0) {return false;}; // konnte nicht abteilen text += tText.substring(0, Index); // Wenn ich innerhalb eines Wortes abteile muss ein '-' eingefügt werden // Wenn hier ein Indexüberlauf auftritt, dann war ein Beistrich der letzte Buchstabe! (bereits ausgeschlossen!) if ((MetaChars.indexOf(tText.charAt(Index)) == -1) && (MetaChars.indexOf(tText.charAt(Index-1)) == -1)) { text += LineBreak;}; text += NewLine; //5g tText = tText.substring(Index).trim(); // Leerzeichen am Beginn muss weg }; // while (length) text += tText; return true; } // forceLines //**************************************************************** //**************************************************************** // checkChars überprüft alle Regeln, die mit auftretenden Zeichen zusammenhängen: // * Nur Buchstaben und ' ,;.()"' dürfen auftreten // * Kein Buchstabe darf öfter als 3 mal hintereinander vorkommen // * ,;". werden vereinfacht, d.h. nur einmal ausgegeben // Die Methode unterscheidet keine Groß-/Kleinschreibung (steht ja bei 3061 nicht in den Spezifikationen) private static boolean checkChars() { if (text.length() == 0) {return true;}; // :-) //6a int count = 1; // enthält die Anzahl der aufeinanderfolgenden BUCHSTABEN int prevLetter, prevSimplify; // Index des vorherigen Zeichens (Buchstabe bzw. zu vereinfachend) int curLetter, curSimplify; // Index des aktuellen Zeichens (Buchstabe bzw. zu vereinfachend) //6b // i = 0; Die folgenden Zeilen entsprechen den for-Operationen auf dem ersten Zeichen (natürlich ohne Vergleiche) char curChar = text.charAt(0); // so muss charAt() nur 1 mal aufgerufen werden prevLetter = lLetters.indexOf(curChar); // Hier könnte die G/K-Schreibung beachtet werden... if (prevLetter == -1) {prevLetter = uLetters.indexOf(curChar);}; if (prevLetter == MetaChars.indexOf(curChar)) {return false;}; // nämlich == -1 prevSimplify = Simplify.indexOf(curChar); for (int i = 1; i < text.length(); i++) { //6c curChar = text.charAt(i); curLetter = lLetters.indexOf(curChar); // Hier könnte die G/K-Schreibung beachtet werden... if (curLetter == -1) {curLetter = uLetters.indexOf(curChar);}; if (curLetter == MetaChars.indexOf(curChar)) {return false;}; // nämlich == -1 curSimplify = Simplify.indexOf(curChar); //6d if ((curLetter != -1) && (curLetter == prevLetter)) // gleicher Buchstabe { if (++count > 3) {return false;}; } else {count = 1;}; //6e if ((curSimplify != -1) && (curSimplify == prevSimplify)) // gleiche ,;." { text = text.substring(0, i) + text.substring(i+1); i--; // weil das nächste Zeichen jetzt wieder an der selben Stelle ist } else // if (Simplify) { prevLetter = curLetter; prevSimplify = curSimplify; }; // if (Simplify) }; // for (i) return true; } // checkChars //**************************************************************** //**************************************************************** // findErrors überprüft alle Fehler, die durch das Suchen von substrings gefunden werden: // * ,; und ;, wird , andere Kombinationen sind nicht erlaubt (,;, oder ;,;) // * " und ( müssen wieder geschlossen werden private static boolean findErrors() { int cIndex = 0; // Zwischenspeicher für einen indexOf()-Wert //7a while (-1 != (cIndex = text.indexOf(",;", cIndex))) { // Indexüberläufe sind im Folgenden unwichtig: try {if (text.charAt(cIndex-1) == ';') {return false;};} catch (Exception e) {}; // ;,; try {if (text.charAt(cIndex+2) == ',') {return false;};} catch (Exception e) {}; // ,;, text = text.substring(0, ++cIndex) + text.substring(cIndex+1); }; // while cIndex = 0; while (-1 != (cIndex = text.indexOf(";,", cIndex))) { text = text.substring(0, cIndex) + text.substring(++cIndex); }; // while //7b int temp = 0; // Anzahl der " // BEACHTE: cIndex hat hier den Wert -1 while (-1 != (cIndex = text.indexOf("\"", cIndex+1))) {temp++;}; if (1 == (temp %= 2)) {return false;}; //7c // int temp = 0; // GIBTS SCHON!: Index der zuletzt "verwendeten" schließenden Klammer // BEACHTE: cIndex hat hier den Wert -1 while (-1 != (cIndex = text.indexOf("(", cIndex+1))) { if (-1 == (temp = text.indexOf(")", ((cIndex > temp)?cIndex:temp+1)))) {return false;}; }; // if (cIndex!=-1) return true; } // findErrors //**************************************************************** //**************************************************************** // checkWords überprüft alle Regeln, die mit Wörtern und Strings zusammenhängen: // * Ein String darf nicht nur aus Interpunktionszeichen bestehen // * " darf Anfang oder am Ende des Strings stehen // * .;) dürfen ausschließlich am Ende eines Strings stehen // * Am Ende darf vor und/oder nach ) bzw " noch eines aus .,; stehen // * ( darf nur am Anfang eines Strings stehen // * , darf nicht am Anfang stehen (nur zwischen Wörtern oder am Ende -> s.o.) // * Großbuchstaben nur am Anfang eines Wortes // * Allererster Buchstabe muss groß sein // * Ein Wort hat zwischen 2 und 12 Buchstaben (jeweils inklusive) // * Hinter dem letzten Wort sind , und ; zu entfernen // * Wenn hinter dem letzten Wort kein Punkt steht, ist einer anzuhängen private static boolean checkWords() { //8a switch (text.length()) { case 0: wordCount = 0; return true; // :-) case 1: return false; // Ein Wort muss zwei Buchstaben haben! // Wegen der gleichzeitigen Führung dreier Zeichen ist der Trivialfall gleich hier: case 2: { if ((uLetters.indexOf(text.charAt(0)) >= 0) && (lLetters.indexOf(text.charAt(1)) >= 0)) { wordCount = 1; text += '.'; return true; } else { return false; }; // else }; // case 2 }; // switch //8b boolean letterFound = false; // Buchstabe im String gefunden (nur Interpunktionszeichen verboten!) int letterCount = 0; // Anzahl der Buchstaben im Wort wordCount = 0; // Das erste und letzte Zeichen wird außerhalb der Schleife behandelt! char prevChar = text.charAt(0); // vorhergehendes (also (i-2)tes) Zeichen switch (prevChar) { case '(': case '"': break; // sicher erlaubt case ',': case ';': case '.': case ')': return false; // sicher verboten default: // Buchstaben: { if (uLetters.indexOf(prevChar) >= 0) { letterFound = true; letterCount = 1; } else { return false; // Kleinbuchstabe als 1. Zeichen }; // if }; // default }; // switch char curChar = prevChar; // aktuelles (also (i-1)tes) Zeichen char nextChar = text.charAt(1); // nächstes (also i-tes) Zeichen // kein Fehler, weil length()==1 bereits ausgeschlossen! //8c for (int i = 2; i < text.length(); i++) // i wird um 1 zu hoch gezählt um (i < text.length()-1) zu vermeiden! { prevChar = curChar; curChar = nextChar; nextChar = text.charAt(i); //8d if (MetaChars.indexOf(curChar) == -1) // Buchstaben (aber MetaChars ist kürzer als Letters) { if (letterCount == 0) { if ((wordCount == 0) && (uLetters.indexOf(curChar) == -1)) {return false;}; // 1. Buchstabe muss groß sein letterFound = true; letterCount = 1; } else // if (LetterCount) { if (uLetters.indexOf(curChar) >= 0) {return false;}; // Großbuchstabe nur am Wortanfang if (letterCount++ == maxLetterCount) {return false;}; }; // if (LetterCount) } else // if (MetaChars) { switch (curChar) { //8e case '"': // Nur am Anfang oder Ende eines STRINGS if ((prevChar != Space) && (nextChar != Space) && (CommaSemiDot.indexOf(nextChar) == -1)) { return false; }; // if (Anfang || Ende) if (letterCount == 1) {return false;}; // minLetterCount = 2 if (letterCount > 1) { letterCount = 0; wordCount++; }; // if (LetterCount) break; //8f case '(': // Nur am Anfang eines STRINGS if (prevChar != Space) {return false;}; break; //8g case ')': // Nur am Ende eines STRINGS if ((nextChar != Space) && (CommaSemiDot.indexOf(nextChar) == -1)) {return false;}; if (letterCount == 1) {return false;}; // minLetterCount = 2 if (letterCount > 1) { letterCount = 0; wordCount++; }; // if (LetterCount) break; //8h case ';': // Dürfen nicht VOR einem Wort stehen, sonst wie ',' case '.': if (MetaChars.indexOf(nextChar) == -1) {return false;}; case ',': // Muss HINTER einem Wort oder " oder ) stehen switch (letterCount) { case 0: // Muss zwischen " oder ) und LEERZEICHEN stehen if (((prevChar != '"') && (prevChar != ')')) || (nextChar != Space)) {return false;}; break; case 1: return false; // minLetterCount = 2 default: { letterCount = 0; wordCount++; }; // default (letterCount) }; // switch (letterCount) break; //8i case ' ': // trennt die STRINGS if (!letterFound) {return false;}; // String darf nicht nur aus Interpunktionszeichen bestehen letterFound = false; if (letterCount == 1) {return false;}; // minLetterCount = 2 if (letterCount > 1) { letterCount = 0; wordCount++; }; // if (LetterCount) break; default: // dürfte nie eintreten (sicher nicht, wenn checkChars() vorher aufgerufen wurde!) { return false;}; }; // switch (curChar) }; // if (Buchstaben) }; // for (i) //8j // Letztes Zeichen wird kontrolliert und ,; nach letztem Wort entfernt und ggf. ein Punkt angehängt if (lLetters.indexOf(nextChar) >= 0) // Letztes Zeichen darf kein Großbuchstabe sein (weil minLetterCount = 2) { if ((letterCount < 1) || (letterCount >= maxLetterCount)) {return false;}; wordCount++; text += '.'; } else // if (lLetters) //8k { if ((!letterFound) || (letterCount == 1)) {return false;}; // nur Interpunktionszeichen im STRING sind verboten // und minLetterCount = 2 switch (nextChar) { case '(': return false; //8l case ',': case ';': case '.': text = text.substring(0, text.length()-1); // .,; hinter dem letzten Wort werden entfernt if (letterCount > 1) { wordCount++; text += '.'; } else // if (letterCount) { switch (curChar) // davor nur ) oder " { case '"': case ')': // davor müssten , oder ; noch entfernt werden (weil nach letztem Wort) switch (prevChar) //8m { case ',': case ';': text = text.substring(0, text.length()-2) + curChar + '.'; break; //8n case '.': // falls oben ein '.' entfernt wurde muss der jetzt wieder hin if (nextChar == '.') {text += '.';}; // sonst nicht (weil hinter dem letzten Wort eh einer ist) break; //8o default: // vor [")|.,;] steht ein Buchstabe (eigentlich nur mehr vor [")]) { text += '.';}; }; // switch (prevChar) break; default: { return false;}; }; // switch (curChar) }; // if (LetterCount) break; //8p case '"': case ')': // davor müssten , oder ; noch entfernt werden (weil nach letztem Wort) switch (curChar) { case ',': case ';': text = text.substring(0, text.length()-2) + nextChar + '.'; break; case '.': break; // hinter dem letzten Wort steht eh ein Punkt default: // vor [")] steht ein Buchstabe { wordCount++; text += '.'; }; // default }; // switch (curChar) break; default: // Großbuchstabe am Schluss { return false;}; }; // switch (nextChar) }; // if (lLetters) return true; } // checkWords //**************************************************************** } // Strings