/// <summary> /// Forces the string to word wrap so that each line doesn't exceed the maxLineLength. /// </summary> /// <param name="str">The string to wrap.</param> /// <param name="options">The options used for wrapping a string.</param> /// <returns></returns> public static string Wrap(this string str, StringWrapOptions options) { var lines = WrappedLines(str, options); var wrapped = string.Join(Environment.NewLine, lines); // Any of the line ending combos will be excluded if at the end of the line. if (str == null) { /* Ignore */ } else if (str.EndsWith("\r\n")) { wrapped += "\r\n"; } else if (str.EndsWith("\n\r")) { wrapped += "\r\n"; } else if (str.EndsWith("\r")) { wrapped += "\r"; } else if (str.EndsWith("\n")) { wrapped += "\n"; } return(wrapped); }
/// <summary> /// Forces the string to word wrap so that each line doesn't exceed the maxLineLength. /// </summary> /// <param name="str">The string to wrap.</param> /// <param name="options">The options used for wrapping a string.</param> /// <returns></returns> public static IEnumerable <string> WrappedLines(this string str, StringWrapOptions options) { if (string.IsNullOrEmpty(str)) { return new string[] { } } ; if (options.MaxWidth <= 0) { return new string[] { str } } ; var prefix = options.Prefix ?? ""; // Make sure we have something so we don't have to keep checking for null. var prefixWidth = MeasureWidth(prefix, options.TabWidth); if (prefixWidth >= options.MaxWidth) { throw new ArgumentException("The width of the prefix must be less than the max width of the line.", "options"); } var lines = new List <string>(); foreach (string line in str.Lines()) { var lineWidth = 0; if (line.Trim() == "") { // Empty line. Just use an empty string in case there is white space // wider than the line. We don't want to wrap white spaces if that // is all that there is on the line since the user won't see it. lines.Add(""); continue; } // We want to keep any white space at the front of the line, but the // white space at the end could cause an extra line that appears empty. //var chars = line.TrimEnd(); var chars = line; var sb = new StringBuilder(); // Iterate through each character on the line so that we // can adjust for TABs and other odd characters. for (var i = 0; i < chars.Length; i++) { var ch = chars[i]; var charWidth = 1; if (ch == '\t') { // Tabs have variable width based on the max width they allow. // This allows text to have something that looks like columns // It's not recommended to have embedded TABs in text for wrapped // lines, but we need to support it. charWidth = CalcTabWidth(lineWidth, options.TabWidth); } else if (char.IsControl(ch)) { // TAB is considered a control character, but it can be printed, so put this check in the else. // Ignore control characters. They aren't printed, and don't add to the length of the string. continue; } // Check to see if adding this char will push the width of the line past the max. if (lineWidth + charWidth <= options.MaxWidth) { sb.Append(ch); lineWidth += charWidth; } else if (char.IsWhiteSpace(ch)) { // If this is a white space, then we know we are at the end of a word. lines.Add(sb.ToString()); sb.Clear(); sb.Append(prefix); // Ignore white space at beginning of new wrapped line. // It would make the left column of text appear jagged. lineWidth = prefixWidth; } else { // Need to find the beginning of the current word and remove it from // the line that we are building. We'll add it to the new line instead. // The prefix is not included when finding a whitespace character. var idx = -1; for (var j = sb.Length - 1; j >= prefix.Length; j--) { if (char.IsWhiteSpace(sb[j])) { idx = j; break; } } // There weren't any white space characters or only the first char is a white space. // Unable to break at word boundary, so break the word at the character. if (idx <= 0) { lines.Add(sb.TrimEnd()); // Don't want any TABs at the end of the line causing problems. sb.Clear(); lineWidth = prefixWidth + charWidth; sb.Append(prefix + ch); } else { lines.Add(sb.Substring(0, idx)); var end = sb.Substring(idx + 1); sb.Clear(); sb.Append(prefix + end); // We know there are no TABs (white space) or control chars, so we can assume all chars have length of 1. lineWidth = prefixWidth + end.Length + charWidth; sb.Append(ch); } } } // Add the end of the line. if (sb.Trim() != "") { lines.Add(sb.ToString()); } } return(lines); }