22

特に複数行のテキストが多い場合は、C# で @"strings" を使用するのが大好きです。唯一の煩わしさは、これを行うとコードの書式設定がおかしくなることです。これは、美しく書式設定されたコードのインデントを使用する代わりに、2 行目以降の行が完全に左に押し出されるためです。これは仕様であることはわかっていますが、実際のタブ/スペースを出力に追加せずに、これらの行をインデントできるようにするオプション/ハックの方法はありますか?

追加例:

        var MyString = @" this is 
a multi-line string
in c#.";

私の変数宣言は「正しい」深さまでインデントされていますが、文字列の 2 行目以降は左マージンに押し込まれているため、コードは見苦しくなります。2行目と3行目の先頭にタブを追加することもできますが、文字列自体にそれらのタブが含まれてしまいます...意味がありますか?

4

4 に答える 4

1

textwrap.dedentこれは、可能な限り模倣しようとする長めのソリューションです。最初の行はそのまま残され、インデントされないことが期待されます。( doctest -csharpを使用して、doctests に基づいて単体テストを生成できます。)

/// <summary>
/// Imitates the Python's
/// <a href="https://docs.python.org/3/library/textwrap.html#textwrap.dedent">
/// <c>textwrap.dedent</c></a>.
/// </summary>
/// <param name="text">Text to be dedented</param>
/// <returns>array of dedented lines</returns>
/// <code doctest="true">
/// Assert.That(Dedent(""), Is.EquivalentTo(new[] {""}));
/// Assert.That(Dedent("test me"), Is.EquivalentTo(new[] {"test me"}));
/// Assert.That(Dedent("test\nme"), Is.EquivalentTo(new[] {"test", "me"}));
/// Assert.That(Dedent("test\n  me"), Is.EquivalentTo(new[] {"test", "  me"}));
/// Assert.That(Dedent("test\n  me\n    again"), Is.EquivalentTo(new[] {"test", "me", "  again"}));
/// Assert.That(Dedent("  test\n  me\n    again"), Is.EquivalentTo(new[] {"  test", "me", "  again"}));
/// </code>
private static string[] Dedent(string text)
{
    var lines = text.Split(
        new[] {"\r\n", "\r", "\n"},
        StringSplitOptions.None);

    // Search for the first non-empty line starting from the second line.
    // The first line is not expected to be indented.
    var firstNonemptyLine = -1;
    for (var i = 1; i < lines.Length; i++)
    {
        if (lines[i].Length == 0) continue;

        firstNonemptyLine = i;
        break;
    }

    if (firstNonemptyLine < 0) return lines;

    // Search for the second non-empty line.
    // If there is no second non-empty line, we can return immediately as we
    // can not pin the indent.
    var secondNonemptyLine = -1;
    for (var i = firstNonemptyLine + 1; i < lines.Length; i++)
    {
        if (lines[i].Length == 0) continue;

        secondNonemptyLine = i;
        break;
    }

    if (secondNonemptyLine < 0) return lines;

    // Match the common prefix with at least two non-empty lines
    
    var firstNonemptyLineLength = lines[firstNonemptyLine].Length;
    var prefixLength = 0;
    
    for (int column = 0; column < firstNonemptyLineLength; column++)
    {
        char c = lines[firstNonemptyLine][column];
        if (c != ' ' && c != '\t') break;
        
        bool matched = true;
        for (int lineIdx = firstNonemptyLine + 1; lineIdx < lines.Length; 
                lineIdx++)
        {
            if (lines[lineIdx].Length == 0) continue;
            
            if (lines[lineIdx].Length < column + 1)
            {
                matched = false;
                break;
            }

            if (lines[lineIdx][column] != c)
            {
                matched = false;
                break;
            }
        }

        if (!matched) break;
        
        prefixLength++;
    }

    if (prefixLength == 0) return lines;
    
    for (var i = 1; i < lines.Length; i++)
    {
        if (lines[i].Length > 0) lines[i] = lines[i].Substring(prefixLength);
    }

    return lines;
}
于 2020-11-20T18:15:11.967 に答える