Question

I need to indent multiple lines of text (in contrast to this question for a single line of text).

Let's say this is my input text:

First line
  Second line
Last line

What I need is this result:

    First line
      Second line
    Last line

Notice the indentation in each line.

This is what I have so far:

var textToIndent = @"First line
  Second line
Last line.";
var splittedText = textToIndent.Split(new string[] {Environment.NewLine}, StringSplitOptions.None);
var indentAmount = 4;
var indent = new string(' ', indentAmount);
var sb = new StringBuilder();
foreach (var line in splittedText) {
    sb.Append(indent);
    sb.AppendLine(line);
}
var result = sb.ToString();

Is there a safer/simpler way to do it?

My concern is in the split method, which might be tricky if text from Linux, Mac or Windows is transfered, and new lines might not get splitted correctly in the target machine.

Was it helpful?

Solution

Since you are indenting all the lines, how about doing something like:

var result = indent + textToIndent.Replace("\n", "\n" + indent);

Which should cover both Windows \r\n and Unix \n end of lines.

OTHER TIPS

Just replace your newline with newline + indent:

var indentAmount = 4;
var indent = new string(' ', indentAmount);
textToIndent = indent + textToIndent.Replace(Environment.NewLine, Environment.NewLine + indent);

The following solution may seem long-winded compared to other solutions posted here; but it has a few distinct advantages:

  • It will preserve line separators / terminators exactly as they are in the input string.
  • It will not append superfluous indentation characters at the end of the string.
  • It might run faster, as it uses only very primitive operations (character comparisons and copying; no substring searches, nor regular expressions). (But that's just my expectation; I haven't actually measured.)
static string Indent(this string str, int count = 1, char indentChar = ' ')
{
    var indented = new StringBuilder();
    var i = 0;
    while (i < str.Length)
    {
        indented.Append(indentChar, count);
        var j = str.IndexOf('\n', i + 1);
        if (j > i)
        {
            indented.Append(str, i, j - i + 1);
            i = j + 1;
        }
        else
        {
            break;
        }
    }
    indented.Append(str, i, str.Length - i);
    return indented.ToString();
}

Stakx's answer got me thinking about not appending superfluous indentation characters. And I think is best to avoid those characters not only at the end, but also in the middle and beginning of the string (when that's all that line has).

I used a Regex to replace new lines only if they are not followed by another new line, and another Regex to avoid adding the first indent in case the string begins with a new line:

Regex regexForReplace = new Regex(@"(\n)(?![\r\n])");
Regex regexForFirst = new Regex(@"^([\r\n]|$)");

string Indent(string textToIndent, int indentAmount = 1, char indentChar = ' ')
{
    var indent = new string(indentChar, indentAmount);
    string firstIndent = regexForFirst.Match(textToIndent).Success ? "" : indent;
    return firstIndent + regexForReplace.Replace(textToIndent, @"$1" + indent);
}

I create the Regexs outside the method in order to speed up multiple replacements.

This solution can be tested at: https://ideone.com/9yu5Ih

If you need a string extension that adds a generic indent to a multi line string you can use:

public static string Indent(this string input, string indent)
{
    return string.Join(Environment.NewLine, input.Split(Environment.NewLine).Select(item => string.IsNullOrEmpty(item.Trim()) ? item : indent + item));
}

This extension skips empty lines. This solution is really simple to understand if you know linq and it's more simple to debug and change if you need to adapt it to different scopes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top