简体   繁体   English

c#中逐字字符串的多行格式(前缀为@)

[英]multiline formatting for verbatim strings in c# (prefix with @)

I love using the @"strings" in c#, especially when I have a lot of multi-line text.我喜欢在 c# 中使用 @"strings",尤其是当我有很多多行文本时。 The only annoyance is that my code formatting goes to doodie when doing this, because the second and greater lines are pushed fully to the left instead of using the indentation of my beautifully formatted code.唯一的烦恼是我的代码格式在这样做时会变得乱七八糟,因为第二行和更大的行被完全推到左边,而不是使用我格式优美的代码的缩进。 I know this is by design, but is there some option/hack way of allowing these lines to be indented, without adding the actual tabs/spaces to the output?我知道这是设计使然,但是是否有一些选项/hack 方法可以让这些行缩进,而不会将实际的制表符/空格添加到输出中?

adding example:添加示例:

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

My variable declaration is indented to the "correct" depth, but the second and further lines in the string get pushed to the left margin- so the code is kinda ugly.我的变量声明缩进到“正确”的深度,但是字符串中的第二行和更多行被推到左边距 - 所以代码有点难看。 You could add tabs to the start of line 2 and 3, but the string itself would then contain those tabs... make sense?您可以在第 2 行和第 3 行的开头添加制表符,但是字符串本身将包含这些制表符……有意义吗?

How about a string extension?字符串扩展怎么样? Update: I reread your question and I hope there is a better answer.更新:我重读了您的问题,希望有更好的答案。 This is something that bugs me too and having to solve it as below is frustrating but on the plus side it does work.这也是让我烦恼的事情,并且必须如下解决它令人沮丧,但从好的方面来说它确实有效。

using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    public static class StringExtensions
    {
        public static string StripLeadingWhitespace(this string s)
        {
            Regex r = new Regex(@"^\s+", RegexOptions.Multiline);
            return r.Replace(s, string.Empty);
        }
    }
}

And an example console program:和一个示例控制台程序:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string x = @"This is a test
                of the emergency
                broadcasting system.";

            Console.WriteLine(x);

            Console.WriteLine();
            Console.WriteLine("---");
            Console.WriteLine();

            Console.WriteLine(x.StripLeadingWhitespace());

            Console.ReadKey();
        }
    }
}

And the output:和输出:

This is a test
                of the emergency
                broadcasting system.

---

This is a test
of the emergency
broadcasting system.

And a cleaner way to use it if you decide to go this route:如果您决定走这条路,还有一种更清洁的使用方式:

string x = @"This is a test
    of the emergency
    broadcasting system.".StripLeadingWhitespace();
// consider renaming extension to say TrimIndent() or similar if used this way

Cymen has given the right solution. Cymen 给出了正确的解决方案。 I use a similar approach as derived from Scala's stripMargin() method.我使用了一种源自 Scala 的 stripMargin() 方法的类似方法。 Here's what my extension method looks like:这是我的扩展方法的样子:

public static string StripMargin(this string s)
{
    return Regex.Replace(s, @"[ \t]+\|", string.Empty);
}

Usage:用法:

var mystring = @"
        |SELECT 
        |    *
        |FROM
        |    SomeTable
        |WHERE
        |    SomeColumn IS NOT NULL"
    .StripMargin();

Result:结果:

SELECT 
    *
FROM
    SomeTable
WHERE
    SomeColumn IS NOT NULL

I can't think of an answer that would completely satisfy your question, however you could write a function that strips leading spaces from lines of text contained in a string and call it on each creation of such a string.我想不出一个可以完全满足您的问题的答案,但是您可以编写一个函数,从字符串中包含的文本行中去除前导空格,并在每次创建此类字符串时调用它。

var myString = TrimLeadingSpacesOfLines(@" this is a 
    a multi-line string
    in c#.");

Yes it is a hack, but you specified your acceptance of a hack in your question.是的,这是一次黑客攻击,但您在问题中指定了接受黑客攻击。

Here is a longish solution which tries to mimic textwrap.dedent as much as possible.这是一个textwrap.dedent解决方案,它试图尽可能地模仿textwrap.dedent The first line is left as-is and expected not to be indented.第一行保持原样,预计不会缩进。 (You can generate the unit tests based on the doctests using doctest-csharp .) (您可以使用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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM