C# :: Aufgabe #62 :: Lösung #1
1 Lösung

#62
Spaltenbreite und Blocksatz
Anfänger - C#
von bibir
- 03.09.2014 um 08:33 Uhr
Ein vorgegebener Text soll eingelesen und in einer bestimmten Spaltenbreite wieder ausgegeben werden.
Die Spaltenbreite N wird als Eingabeparameter vorgegeben. Der Text besteht aus "Wörtern", die durch Leerzeichen (Blank) getrennt sind. Unter einem "Wort" wird hier eine beliebige zusammenhängende Zeichenkette verstanden, wobei jedes Zeichen eine Druckstelle einnimmt.
Der Text soll ausgerichtet werden an den beiden Spaltenrändern, und die zusätzlich einzuführenden Blanks sollen möglichst gleichmäßig auf die Zwischenräume zwischen den Wörtern verteilt werden.
Der Text beginnt in einer Spalte grundsätzlich linksbündig, Wörter, die länger sind als die Spaltenbreite, werden am rechten Rand ohne Trennzeichen zwangsweise getrennt. Silbentrennung darf nicht durchgeführt werden.
Die Spaltenbreite N wird als Eingabeparameter vorgegeben. Der Text besteht aus "Wörtern", die durch Leerzeichen (Blank) getrennt sind. Unter einem "Wort" wird hier eine beliebige zusammenhängende Zeichenkette verstanden, wobei jedes Zeichen eine Druckstelle einnimmt.
Der Text soll ausgerichtet werden an den beiden Spaltenrändern, und die zusätzlich einzuführenden Blanks sollen möglichst gleichmäßig auf die Zwischenräume zwischen den Wörtern verteilt werden.
Der Text beginnt in einer Spalte grundsätzlich linksbündig, Wörter, die länger sind als die Spaltenbreite, werden am rechten Rand ohne Trennzeichen zwangsweise getrennt. Silbentrennung darf nicht durchgeführt werden.
#1

von eulerscheZhl (5230 Punkte)
- 24.11.2014 um 20:19 Uhr
Optimierungskriterien (hierarchisch geordnet):
1. So wenig Zeilenumbrüche wie möglich
2. So wenig Leerzeichen am Ende einer Zeile wie möglich (keine kurzen Worte allein in eine Zeile schreiben)
3. So wenig aufeinanderfolgende Leerzeichen wie möglich
Da gibt es eine Menge Fälle zu prüfen, das Programm ist leider zeimlich langsam. Verbesserungsvorschläge sind willkommen.
C#-Code
Ausgabe:
C-Code
1. So wenig Zeilenumbrüche wie möglich
2. So wenig Leerzeichen am Ende einer Zeile wie möglich (keine kurzen Worte allein in eine Zeile schreiben)
3. So wenig aufeinanderfolgende Leerzeichen wie möglich
Da gibt es eine Menge Fälle zu prüfen, das Programm ist leider zeimlich langsam. Verbesserungsvorschläge sind willkommen.

using System; using System.Text; using System.Collections.Generic; namespace trainYourProgrammer { class MainClass { static string FormatColumns(string text, int textWidth, int space) { string[] lines = FormatText (text, textWidth).Split ('\n'); int columnCount = (Console.WindowWidth + space) / (textWidth + space); int lineCount = (lines.Length + columnCount - 1) / columnCount; StringBuilder result = new StringBuilder (); for (int line = 0; line < lineCount; line++) { for (int column = 0; column < columnCount; column++) { if (line + column * lineCount < lines.Length) result.Append (lines [line + column * lineCount]); if (column < columnCount - 1) result.Append (' ', space - 0); } result.AppendLine (); } return result.ToString (); } static string FormatText(string text, int textWidth) { string[] words = text.Split (new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder result = new StringBuilder (); List<string> blockWords = new List<string> (); for (int i = 0; i < words.Length; i++) { if (words [i].Length % textWidth == 0 || words [i].Length % textWidth == textWidth - 1) { result.Append (FormatBlock (blockWords, textWidth)); blockWords.Clear (); } blockWords.Add (words [i]); } result.AppendLine (FormatBlock (blockWords, textWidth)); return result.ToString (); } static string FormatBlock(List<string> words, int textWidth) { int [] wordLength = new int[words.Count]; for (int i = 0; i < wordLength.Length; i++) wordLength [i] = words [i].Length % textWidth; int[] wordStart = new int[wordLength.Length]; int linesNeeded = FillFromBeginning (wordLength, ref wordStart, textWidth, 0, 0); int optimumVal = Review (wordLength, wordStart, textWidth); FitBlockRecurs (wordLength, ref optimumVal, ref wordStart, ref wordStart, linesNeeded, textWidth, 0); //optimale Lösung in Zeilen zerlegen und diese für sich optimieren StringBuilder result = new StringBuilder (); List<string> currWords = new List<string> (); for (int i = 0; i < words.Count; i++) { if (wordStart [i] % textWidth == 0) { //Zeilenanfang result.Append (FitLine(currWords, textWidth)); currWords.Clear (); } currWords.Add (words [i]); } result.Append (FitLine(currWords, textWidth)); //und das letzte Wort nicht vergessen return result.ToString (); } public static string FitLine(List<string> words, int textWidth) { if (words.Count == 0) return ""; string result = String.Join (" ", words); int remainingSpaces = (textWidth * result.Length - result.Length) % textWidth; result = words [0]; for (int i = 1; i < words.Count; i++) { result += " "; //normales Leerzeichen zwischen Wörtern result += new string (' ', remainingSpaces / (words.Count - i)); //Füllzeichen remainingSpaces -= remainingSpaces / (words.Count - i); result += words [i]; } if (words.Count == 1) result += new string (' ', remainingSpaces); for (int i = textWidth; i < result.Length; i+= textWidth + 1) result = result.Insert (i, "\n"); return result + "\n"; } public static int FillFromBeginning(int[] wordLength, ref int[] wordStart, int textWidth, int cursorIndex, int wordIndex) { for (int i = wordIndex; i < wordLength.Length; i++) { if ((cursorIndex + wordLength [i] - 1) / textWidth > cursorIndex / textWidth) //muss in nächste Zeile schreiben cursorIndex = cursorIndex / textWidth * textWidth + textWidth; wordStart [i] = cursorIndex; cursorIndex += wordLength [i]; if (cursorIndex % textWidth != 0) //nicht von selbst in nächster Zeile angekommen cursorIndex++; //Leerzeichen einfügen } return (cursorIndex + textWidth - 1) / textWidth; } public static void FitBlockRecurs (int[] wordLength, ref int optimumVal, ref int[] currSol, ref int[] optimumSol, int linesNeeded, int textWidth, int lastMoved) { for (int move = lastMoved + 1; move < wordLength.Length; move++) { int[] testSolution = new int[wordLength.Length]; for (int i = 0; i < move; i++) testSolution [i] = optimumSol [i]; //schreibe words[move] in nächste Zeile int index = optimumSol [move - 1] / textWidth * textWidth + textWidth; if (FillFromBeginning (wordLength, ref testSolution, textWidth, index, move) > linesNeeded) continue; //es werden mehr Zeilen belegt, als nötig, Abbruch int currVal = Review (wordLength, testSolution, textWidth); if (currVal < optimumVal) { //eine bessere Lösung als die bisherige wurde gefunden optimumVal = currVal; optimumSol = testSolution; } FitBlockRecurs (wordLength, ref optimumVal, ref testSolution, ref optimumSol, linesNeeded, textWidth, move); } } public static int Review(int[] wordLength, int[] wordStart, int textWidth) //Bewertung der Aufteilung. Je kleiner der Wert, desto besser { int result = 0; for (int i = 0; i < wordStart.Length; i++) { if (wordStart [i] % textWidth == 0) {//Zeilenanfang int wordInLine = 1; for (int j = i+1; j < wordStart.Length; j++) if (wordStart [i] / textWidth == wordStart [j] / textWidth) wordInLine++; if (wordInLine == 1) result += (textWidth - wordLength [i]) * 100; //100 Strafpunkte für jedes Leerzeichen am Zeilenende else { //mehrere Wörter in einer Zeile -> (Leerzeichengruppenlaenge -1)^2 Strafpunkte --> ".." ist ein Strafpunkt, "..." sind 4 Punkte, ... int remainingSpaces = (textWidth - wordStart [i + wordInLine - 1]) % textWidth; int maxGroundLength = 0; if (remainingSpaces > 0) maxGroundLength = (wordInLine - 1) / remainingSpaces; result += maxGroundLength * maxGroundLength; } } } return result; } static void Main(string[] args) { string text = "Dies ist ein Typoblindtext. An ihm kann man sehen, ob alle Buchstaben da sind und wie sie aussehen. Manchmal benutzt man Worte wie Hamburgefonts, Rafgenduks oder Handgloves, um Schriften zu testen. Manchmal Sätze, die alle Buchstaben des Alphabets enthalten - man nennt diese Sätze »Pangrams«. Sehr bekannt ist dieser: The quick brown fox jumps over the lazy old dog. Oft werden in Typoblindtexte auch fremdsprachige Satzteile eingebaut (AVAIL® and Wefox™ are testing aussi la Kerning), um die Wirkung in anderen Sprachen zu testen. In Lateinisch sieht zum Beispiel fast jede Schrift gut aus. Quod erat demonstrandum. Seit 1975 fehlen in den meisten Testtexten die Zahlen, weswegen nach TypoGb. 204 § ab dem Jahr 2034 Zahlen in 86 der Texte zur Pflicht werden. Nichteinhaltung wird mit bis zu 245 € oder 368 $ bestraft. Genauso wichtig in sind mittlerweile auch Âçcèñtë, die in neueren Schriften aber fast immer enthalten sind. Ein wichtiges aber schwierig zu integrierendes Feld sind OpenType-Funktionalitäten. Je nach Software und Voreinstellungen können eingebaute Kapitälchen, Kerning oder Ligaturen (sehr pfiffig) nicht richtig dargestellt werden."; Console.WriteLine(FormatColumns(text, 10, 4) + "\n\n"); Console.WriteLine(FormatColumns(text, 15, 5)); } } }
Ausgabe:

Dies ist Sätze, auch frem demonstran 245 € oder unktionali ein Typo die alle dsprachige dum. Seit 368 $ täten. blindtext. Buchstaben Satzteile 1975 bestraft. Je nach An ihm des eingebaut fehlen Genauso Software kann man Alphabets (AVAIL® in den wichtig in und Vorein sehen, enthalten and Wefox™ meisten sind mi stellungen ob alle - man are Testtexten ttlerweile können Buchstaben nennt testing die auch eingebaute da sind diese aussi la Zahlen, Âçcèñtë, Kapitälche und wie Sätze Kerning), weswegen die in n, Kerning sie »Pangrams« um die nach neueren oder aussehen. . Sehr Wirkung in TypoGb. Schriften Ligaturen Manchmal bekannt anderen 204 § aber fast (sehr benutzt ist Sprachen ab dem immer pfiffig) man Worte dieser: zu testen. Jahr 2034 enthalten nicht wie Hamb The quick In Zahlen in sind. Ein richtig d urgefonts, brown fox Lateinisch 86 der wichtiges argestellt Rafgenduks jumps over sieht zum Texte zur aber werden. oder Handg the lazy Beispiel Pflicht schwierig loves, um old dog. fast jede werden. zu inte Schriften Oft werden Schrift Nichteinha grierendes zu testen. in Typo gut aus. ltung wird Feld sind Manchmal blindtexte Quod erat mit bis zu OpenType-F Dies ist ein ist dieser: The demonstrandum. immer enthalten Typoblindtext. quick brown fox Seit 1975 sind. Ein An ihm kann man jumps over the fehlen in wichtiges aber sehen, ob alle lazy old dog. den meisten schwierig zu Buchstaben da Oft werden in Testtexten integrierendes sind und wie Typoblindtexte die Zahlen, Feld sind sie aussehen. auch weswegen OpenType-Funkti Manchmal fremdsprachige nach TypoGb. onalitäten. Je benutzt man Satzteile 204 § ab dem nach Software Worte wie eingebaut Jahr 2034 und Voreinstel Hamburgefonts, (AVAIL® and Zahlen in 86 lungen können Rafgenduks oder Wefox™ are der Texte zur eingebaute Handgloves, um testing aussi Pflicht werden. Kapitälchen, Schriften la Kerning), Nichteinhaltung Kerning oder zu testen. um die Wirkung wird mit bis Ligaturen Manchmal Sätze, in anderen zu 245 € oder (sehr pfiffig) die alle Sprachen zu 368 $ bestraft. nicht richtig Buchstaben testen. In Genauso wichtig dargestellt des Alphabets Lateinisch in sind werden. enthalten sieht mittlerweile - man nennt zum Beispiel auch Âçcèñtë, diese Sätze fast jede die in neueren »Pangrams«. Schrift gut Schriften aber Sehr bekannt aus. Quod erat fast
Kommentare:
Für diese Lösung gibt es noch keinen Kommentar
Seite 1 von 0
1