从StringBuilder的末尾修剪空格而不调用ToString()。修剪()并返回到新的SB

时间:2014-07-15 23:17:42

标签: c# stringbuilder

在不调用ToString()的情况下从StringBuilder的末尾修剪空格的有效方法是什么。修剪()并返回到新的SB new StringBuilder(sb.ToString().Trim())

5 个答案:

答案 0 :(得分:37)

以下是扩展方法,因此您可以这样调用它:

    sb.TrimEnd();

此外,它返回SB实例,允许您链接其他调用(sb.TrimEnd().AppendLine())。

    public static StringBuilder TrimEnd(this StringBuilder sb)
    {
        if (sb == null || sb.Length == 0) return sb;

        int i = sb.Length - 1;
        for (; i >= 0; i--)
            if (!char.IsWhiteSpace(sb[i]))
                break;

        if (i < sb.Length - 1)
            sb.Length = i + 1;

        return sb;
    }

注意:

1)如果为Null或Empty,则返回。

2)如果实际上不需要Trim,我们正在谈论一个非常快速的返回时间,可能最昂贵的调用是对char.IsWhiteSpace的单次调用。因此,在不需要时调用TrimEnd几乎为零,而不是这些ToString()。Trim()返回SB路径。

3)否则,如果需要修剪,最昂贵的是对char.IsWhiteSpace的多次调用(在第一个非空白字符处中断)。当然,循环向后迭代;如果所有都是空白,你最终会得到一个SB.Length为0。

4)如果遇到空格,则i索引保持在循环之外,这允许我们适当地剪切长度。在StringBuilder中,这是非常高效的,它只是设置一个内部长度整数(内部char []保持相同的内部长度。)

UPDATE2:看看 Ryan Emerle 的优秀笔记如下,这些笔记纠正了我的一些误解(SB的内部工作比我做出的要复杂得多):

  

StringBuilder在技术上是char []块的链表。所以   我们最终没有留在LOH。调整长度在技术上不是   简单的更改结束索引,因为如果你移动到另一个   必须维护容量,因此可能需要一个新的块   分配。不过,你只在最后设置了Length属性,   所以这似乎是一个很好的解决方案。   Eric Lippert的相关细节:https://stackoverflow.com/a/6524401/62195

另外,请参阅这篇讨论.NET 4.0新StringBuilder实现的好文章:http://1024strongoxen.blogspot.com/2010/02/net-40-stringbuilder-implementation.html

-------更新--------

下面说明当StringBuilder长度被更改时会发生什么(这里对SB执行的唯一真实操作,以及仅在需要时):

        StringBuilder sb = new StringBuilder("cool  \t \r\n ");

        sb.Capacity.Print(); // 16
        sb.Length.Print();  // 11

        sb.TrimEnd();

        sb.Capacity.Print(); // 16
        sb.Length.Print();  // 4 

在更改Length之后,您可以看到内部数组(m_​​ChunkChars)保持相同的大小,事实上,您可以在调试器中看到它甚至不会覆盖(在这种情况下为空格)字符。他们是孤儿。

答案 1 :(得分:3)

你可以试试这个:

StringBuilder b = new StringBuilder();
b.Append("some words");
b.Append(" to test   ");

int count = 0;
for (int i = b.Length - 1; i >= 0; i--)
{
    if (b[i] == ' ')
        count++;
    else
        break;
}

b.Remove(b.Length - count, count);
string result = b.ToString();

只有在有空格然后突破循环时才会遍历结束。

或者甚至喜欢这样:

StringBuilder b = new StringBuilder();
b.Append("some words");
b.Append(" to test   ");

do
{
    if(char.IsWhiteSpace(b[b.Length - 1]))
    {
         b.Remove(b.Length - 1,1);
    }
}
while(char.IsWhiteSpace(b[b.Length - 1]));

string get = b.ToString();

答案 2 :(得分:0)

public static class StringBuilderExtensions
{
    public static StringBuilder Trim(this StringBuilder builder)
    {
        if (builder.Length == 0)
            return builder;

        var count = 0;
        for (var i = 0; i < builder.Length; i++)
        {
            if (!char.IsWhiteSpace(builder[i]))
                break;
            count++;
        }

        if (count > 0)
        {
            builder.Remove(0, count);
            count = 0;
        }

        for (var i = builder.Length - 1; i >= 0; i--)
        {
            if (!char.IsWhiteSpace(builder[i]))
                break;
            count++;
        }

        if (count > 0)
            builder.Remove(builder.Length - count, count);

        return builder;
    }
}

答案 3 :(得分:0)

要进行全面修整,在StringBuilder级别上执行此操作不是明智的/可取的,而是在ToString时执行此操作,例如使用以下TrimToString实现:

    public static string TrimToString(this StringBuilder sb)
    {
        if (sb == null) return null;

        sb.TrimEnd(); // handles nulle and is very inexpensive, unlike trimstart

        if (sb.Length > 0 && char.IsWhiteSpace(sb[0])) {
            for (int i = 0; i < sb.Length; i++)
                if (!char.IsWhiteSpace(sb[i]))
                    return sb.ToString(i);
            return ""; // shouldn't reach here, bec TrimEnd should have caught full whitespace strings, but ...
        }

        return sb.ToString();
    }

答案 4 :(得分:-1)

StringBuilder myString = new StringBuilder("This is Trim test ");

if (myString[myString.Length - 1].ToString() == " ")
{              
    myString = myString.Remove(myString.Length - 1, 1);
}