Kata Word Wrap mit expliziten Aspekten
using System; | |
using System.Dynamic; | |
using NUnit.Framework; | |
namespace KataWordWrap | |
{ | |
[TestFixture()] | |
public class test_Wrapper | |
{ | |
[TestCase("word", 4, Result="word")] | |
[TestCase("word", 2, Result="wo\nrd")] | |
[TestCase("word", 3, Result = "wor\nd")] | |
[TestCase("wordword", 3, Result="wor\ndwo\nrd")] | |
[TestCase("word word", 4, Result="word\nword")] | |
[TestCase("word word", 5, Result="word\nword")] | |
[TestCase("word word", 6, Result="word\nword")] | |
[TestCase("word wo-rd", 8, Result = "word wo-\nrd")] | |
[TestCase("word word word", 6, Result="word\nword\nword")] | |
[TestCase("word word word", 11, Result="word word\nword")] | |
public string Wrap_single_text(string text, int maxCols) | |
{ | |
return Wrapper.Wrap(text, maxCols); | |
} | |
[TestCase("word11\nword21", 42, Result = "word11\nword21")] | |
[TestCase("word11 word12\nword21 word22", 10, Result="word11\nword12\nword21\nword22")] | |
public string Wrap_multiple_texts(string text, int maxCols) | |
{ | |
return Wrapper.Wrap(text, maxCols); | |
} | |
[TestCase("lineRemainder", 4, "line", "Remainder")] | |
[TestCase("line", 4, "line", "", Description = "End of text")] | |
[TestCase("line", 5, "line", "", Description = "End of text with not enough chars for full line")] | |
[TestCase("", 1, "", "")] | |
public void Break_off_next_line(string text, int maxCols, string line, string remainder) | |
{ | |
var t = Wrapper.Break_off_next_line(text, maxCols); | |
Assert.AreEqual(line, t.Line); | |
Assert.AreEqual(remainder, t.Remainder); | |
} | |
[TestCase("line", "remainder", "line", "remainder", Description = "Perfect break or word too long for line")] | |
[TestCase("line ", "remainder", "line", "remainder", Description = "Trailing space in line")] | |
[TestCase("line", " remainder", "line", "remainder", Description = "Leading space in remainder")] | |
[TestCase("line w", "ord remainder", "line", "word remainder", Description = "Word split at end of line")] | |
[TestCase("line w-", "ord remainder", "line w-", "ord remainder", Description = "Line ends on word breakpoint")] | |
[TestCase("line w-o", "rd remainder", "line w-", "ord remainder", Description = "Split word at breakpoint")] | |
public void Heal_split_word(string line, string remainder, string linedTrimmed, string remainderTrimmed) | |
{ | |
dynamic parts = new ExpandoObject(); | |
parts.Line = line; | |
parts.Remainder = remainder; | |
var healed = Wrapper.Heal_split_word(parts); | |
Assert.AreEqual(linedTrimmed, healed.Line); | |
Assert.AreEqual(remainderTrimmed, healed.Remainder); | |
} | |
[TestCase("", "line", "line", Description = "First line")] | |
[TestCase("new", "line", "new\nline", Description = "Second to last line")] | |
public void Append_line_to_new_text(string newText, string line, string newTextResult) | |
{ | |
Assert.AreEqual(newTextResult, Wrapper.Append_text(newText, line)); | |
} | |
[TestCase("a", 2, "a")] | |
[TestCase("a b", 3, "a b")] | |
[TestCase("a b", 4, "a b")] | |
[TestCase("a b c", 7, "a b c")] | |
[TestCase("a b c", 6, "a b c")] | |
public void Justify(string line, int maxCols, string justifiedLine) | |
{ | |
Assert.AreEqual(justifiedLine, Wrapper.Justify(line, maxCols)); | |
} | |
[TestCase("text1\ntext2", "text1", "text2")] | |
[TestCase("text", "text", "")] | |
public void Get_next_text(string multitext, string text, string remainder) | |
{ | |
var parts = Wrapper.Get_next_text(multitext); | |
Assert.AreEqual(text, parts.Text); | |
Assert.AreEqual(remainder, parts.Remainder); | |
} | |
} | |
} |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Dynamic; | |
namespace KataWordWrap | |
{ | |
// http://codingdojo.org/cgi-bin/wiki.pl?KataWordWrap | |
public class Wrapper | |
{ | |
public static string Wrap(string text, int maxCols) | |
{ | |
return Wrap_multi_text("", text, maxCols); | |
} | |
private static string Wrap_multi_text(string newText, string remainder, int maxCols) | |
{ | |
if (remainder == "") return newText; | |
var parts = Get_next_text(remainder); | |
var wrapped = Wrap_remaining_text("", parts.Text, maxCols); | |
newText = Append_text(newText, wrapped); | |
return Wrap_multi_text(newText, parts.Remainder, maxCols); | |
} | |
internal static dynamic Get_next_text(string multitext) | |
{ | |
dynamic parts = new ExpandoObject(); | |
var eolIndex = multitext.IndexOf("\n"); | |
if (eolIndex < 0) | |
{ | |
parts.Text = multitext; | |
parts.Remainder = ""; | |
return parts; | |
} | |
parts.Text = multitext.Substring(0, eolIndex); | |
parts.Remainder = multitext.Substring(eolIndex + "\n".Length); | |
return parts; | |
} | |
private static string Wrap_remaining_text(string newText, string remainder, int maxCols) | |
{ | |
if (remainder == "") return newText; | |
var parts = Extract_line(remainder, maxCols); | |
parts.Line = Justify(parts.Line, maxCols); | |
newText = Append_text(newText, parts.Line); | |
return Wrap_remaining_text(newText, parts.Remainder, maxCols); | |
} | |
private static dynamic Extract_line(string text, int maxCols) | |
{ | |
var parts = Break_off_next_line(text, maxCols); | |
return Heal_split_word(parts); | |
} | |
internal static string Justify(string line, int maxCols) | |
{ | |
var number_of_spaces_to_insert = maxCols - line.Length; | |
var words = line.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); | |
var wordIndex = 0; | |
while(words.Length > 1 && number_of_spaces_to_insert>0) | |
{ | |
words[wordIndex] = words[wordIndex] + ' '; | |
number_of_spaces_to_insert--; | |
wordIndex = (wordIndex + 1) % (words.Length-1); | |
} | |
return string.Join(" ", words); | |
} | |
internal static string Append_text(string newText, string line) | |
{ | |
return newText + (newText == "" ? "" : "\n") + line; | |
} | |
internal static dynamic Break_off_next_line(string text, int maxCols) | |
{ | |
var line = text.Substring(0, Math.Min(maxCols, text.Length)); | |
var remainder = maxCols < text.Length ? text.Substring(maxCols) : ""; | |
dynamic parts = new ExpandoObject(); | |
parts.Line = line; | |
parts.Remainder = remainder; | |
return parts; | |
} | |
internal static dynamic Heal_split_word(dynamic parts) | |
{ | |
return Has_a_word_been_split(parts) ? Rejoin_head_of_word_with_body_in_remainder(parts) | |
: Trim_line_and_remainder(parts); | |
} | |
private static bool Has_a_word_been_split(dynamic parts) | |
{ | |
return !parts.Line.EndsWith(" ") && !parts.Remainder.StartsWith(" "); | |
} | |
private static dynamic Rejoin_head_of_word_with_body_in_remainder(dynamic parts) | |
{ | |
return Line_ends_with_syllable(parts.Line) ? Rejoin_syllable(parts) | |
: Rejoin_word(parts); | |
} | |
private static bool Line_ends_with_syllable(string line) | |
{ | |
return line.LastIndexOf("-") > line.LastIndexOf(" "); | |
} | |
private static dynamic Rejoin_syllable(dynamic parts) | |
{ | |
var indexOfLastHyphen = parts.Line.LastIndexOf("-"); | |
if (!parts.Line.EndsWith("-") && indexOfLastHyphen >= 0) | |
{ | |
var headOfSplitWord = parts.Line.Substring(indexOfLastHyphen + 1); | |
parts.Line = parts.Line.Substring(0, indexOfLastHyphen + 1); | |
parts.Remainder = headOfSplitWord + parts.Remainder; | |
} | |
return parts; | |
} | |
private static dynamic Rejoin_word(dynamic parts) | |
{ | |
var indexOfLastSpace = parts.Line.LastIndexOf(" "); | |
if (indexOfLastSpace >= 0) | |
{ | |
var headOfSplitWord = parts.Line.Substring(indexOfLastSpace + 1); | |
parts.Line = parts.Line.Substring(0, indexOfLastSpace).TrimEnd(); | |
parts.Remainder = headOfSplitWord + parts.Remainder; | |
} | |
return parts; | |
} | |
private static dynamic Trim_line_and_remainder(dynamic parts) | |
{ | |
parts.Line = parts.Line.TrimEnd(); | |
parts.Remainder = parts.Remainder.TrimStart(); | |
return parts; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment