缩进多行文字

16

我需要缩进多行文本(与此单行文本的问题相反)。

假设这是我的输入文本:

First line
  Second line
Last line

我需要的是这个结果:

    First line
      Second line
    Last line
注意每行的缩进。
到目前为止,我有以下内容:
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();

有没有更安全/更简单的方法可以做到这一点?

我的担心在于分割方法,如果从Linux、Mac或Windows传输文本,可能会很棘手,并且新行可能无法在目标机器上正确拆分。

5个回答

29

既然你要缩进所有行,那么可以这样做:

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

应该覆盖Windows的\r\n和Unix的\n换行符。


6
为了完整起见,一些不常见或传统的系统使用其他“换行符”组合:换行符表示 - Sphinxxx
6
太好了,谢谢!关于"\n",我不确定,但事实上,如果你只需要处理Windows和Unix系统发送的字符串,那么"\n"可能更好,因为这将解析由另一个系统发送的字符串。否则,Windows环境将不会替换Unix换行符。但如果您需要支持Mac OS 9(或其他),我认为Environment.NewLine会更好用。 - Mariano Desanze
@aloisdg,我通常建议不要使用Environment.NewLine,并选择显式的选择或更好的换行符中立处理方式,因为1)Environment.NewLine在非Windows的“Web内容”中会失败,在Windows上也会失败“Unix内容”。在这种情况下,“\n”的选择也不正确(因为它可能会错误地拆分“\r\n”),但这并不能使Environment.NewLine成为更好的选择:} - user2864740
1
这段代码最好使用换行模式中性的方式编写(参见上文):var result = indent + Regex.Replace(textToIndent, @"\r?\n", m => m.Groups[0] + indent); - user2864740

4
只需要用换行符加上缩进代替原来的换行符即可:
var indentAmount = 4;
var indent = new string(' ', indentAmount);
textToIndent = indent + textToIndent.Replace(Environment.NewLine, Environment.NewLine + indent);

这段代码最好以换行模式中立的方式编写(请参见评论中被接受的答案):var result = indent + Regex.Replace(textToIndent, @"\r?\n", m => m.Groups[0] + indent); - 它没有涵盖旧版 Mac 的情况,但此时许多编辑器/查看器也无法正常工作 :} - user2864740

2

与其他在此发布的解决方案相比,以下解决方案可能看起来有些冗长;但它具有一些明显的优点:

  • 它将完全保留输入字符串中的行分隔符/终止符。
  • 它不会在字符串末尾附加多余的缩进字符。
  • 可能运行更快,因为它仅使用非常原始的操作(字符比较和复制;没有子字符串搜索或正则表达式)。 (但这只是我的期望;我实际上还没有测量过。)
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();
}

0

Stakx的回答让我想到了不要添加多余的缩进字符。我认为最好不仅在字符串末尾,而且在中间和开头也避免使用这些字符(当该行只有这些字符时)。

我使用了一个正则表达式来替换换行符,但仅当它们后面没有另一个换行符时,并使用另一个正则表达式来避免在字符串以换行符开头时添加第一个缩进:

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);
}

我在方法外创建正则表达式 s 以加快多次替换。

该解决方案可在此进行测试: https://ideone.com/9yu5Ih


0
如果您需要一个字符串扩展,可以向多行字符串添加通用缩进,您可以使用以下代码:
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));
}

这个扩展跳过空行。 如果你了解linq,这个解决方案非常容易理解,如果需要适应不同的范围,调试和更改也更加简单。


2
请不要仅仅发布代码作为答案,还要提供解释您的代码是如何解决问题的。带有解释的答案通常质量更高,更有可能吸引赞同。 - Mark Rotteveel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接