如何使用 StringBuilder 在字符串前添加内容?

164

我知道我们可以使用StringBuilder来追加字符串。那么,我们是否可以使用StringBuilder在字符串前面添加字符串(即往字符串前面添加字符串),以便保持StringBuilder提供的性能优势呢?

12个回答

243
使用将位置参数设置为0的insert方法与预先处理(即在开头插入)相同。
C#示例:varStringBuilder.Insert(0, "someThing"); Java示例:varStringBuilder.insert(0, "someThing"); 它适用于C#Java

7
StringBuilder 的 insert 方法用于在指定位置插入字符串或其他数据类型的值。第一个参数是插入位置的索引,第二个参数是要插入的值。可以重载该方法以支持各种数据类型和字符序列。完整文档请参考:http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html#insert(int,%20boolean) - Matthew Farwell
相关API的正确JavaDoc为:http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuilder.html#insert(int,%20java.lang.CharSequence%29 - Sled

36

在一般情况下,将一个字符串作为前缀添加到另一个字符串中通常需要将插入点之后的所有内容复制回到支持数组中,因此它不像将字符串附加到末尾那么快速。

但是你可以用以下Java代码实现(在C#中也一样,只是方法名为Insert):

aStringBuilder.insert(0, "newText");

15
如果您需要高性能和大量的prepends,您需要编写自己的StringBuilder版本(或使用别人的)。使用标准的StringBuilder(虽然技术上可以以不同的方式实现),插入需要在插入点之后复制数据。插入n个文本片段可能需要O(n^2)时间。
一种朴素的方法是在备用char[]缓冲区中添加偏移量和长度。当没有足够的空间进行prepend时,将数据向上移动超过严格必要的距离。这可以将性能降至O(n log n)(我认为)。更精细的方法是使缓冲区成为循环的。通过这种方式,数组两端的剩余空间变得连续。

9

如果你想在Java的StringBuilder类中使用prepend功能,可以采取以下方法:

StringBuilder str = new StringBuilder();
str.Insert(0, "text");

7

您可以尝试使用扩展方法:

/// <summary>
/// kind of a dopey little one-off for StringBuffer, but 
/// an example where you can get crazy with extension methods
/// </summary>
public static void Prepend(this StringBuilder sb, string s)
{
    sb.Insert(0, s);
}

StringBuilder sb = new StringBuilder("World!");
sb.Prepend("Hello "); // Hello World!

6
你可以反向构建字符串,然后反转结果。这样做的时间复杂度为O(n),而不是最坏情况下的O(n^2)。

5
只有在拼接单个字符时才能奏效。否则,您将需要反转每个已拼接的字符串,这可能会耗费大部分或全部节省的时间,具体取决于字符串的大小和数量。 - Sled

4

如果我理解正确,插入方法看起来可以满足您的需求。只需在偏移量为0的位置插入字符串即可。


4

我没有使用过,但Java绳索听起来非常有趣。该项目名称是一个双关语,为了更好地处理工作,使用绳索而不是字符串。可以避免在前缀和其他操作中的性能损失。如果您将要频繁进行此类操作,则值得一看。

绳索是字符串的高性能替代品。该数据结构的详细描述可在“绳索:字符串的替代方法”中找到,它提供比常见字符串修改(如添加前缀、追加、删除和插入)的String和StringBuffer更好的渐近性能。像Strings一样,绳索是不可变的,因此非常适合用于多线程编程。


3

尝试使用Insert()函数。

StringBuilder MyStringBuilder = new StringBuilder("World!");
MyStringBuilder.Insert(0,"Hello "); // Hello World!

2
根据其他评论,没有标准的快速方法来完成这个任务。使用StringBuilder的.Insert(0, "text")仅比痛苦缓慢的字符串连接快1-3倍(基于>10000个连接),因此下面是一个类,可以更快地添加前缀数千次!
我还包括了一些其他基本功能,如append()subString()length()等。追加和添加前缀的速度都比StringBuilder的追加慢两倍到三倍。像StringBuilder一样,当文本溢出旧缓冲区大小时,该类中的缓冲区将自动增加。
代码已经进行了很多测试,但我不能保证它没有错误。
class Prepender
{
    private char[] c;
    private int growMultiplier;
    public int bufferSize;      // Make public for bug testing
    public int left;            // Make public for bug testing
    public int right;           // Make public for bug testing
    public Prepender(int initialBuffer = 1000, int growMultiplier = 10)
    {
        c = new char[initialBuffer];
        //for (int n = 0; n < initialBuffer; n++) cc[n] = '.';  // For debugging purposes (used fixed width font for testing)
        left = initialBuffer / 2;
        right = initialBuffer / 2;
        bufferSize = initialBuffer;
        this.growMultiplier = growMultiplier;
    }
    public void clear()
    {
        left = bufferSize / 2;
        right = bufferSize / 2;
    }
    public int length()
    {
        return right - left;
    }

    private void increaseBuffer()
    {
        int nudge = -bufferSize / 2;
        bufferSize *= growMultiplier;
        nudge += bufferSize / 2;
        char[] tmp = new char[bufferSize];
        for (int n = left; n < right; n++) tmp[n + nudge] = c[n];
        left += nudge;
        right += nudge;
        c = new char[bufferSize];
        //for (int n = 0; n < buffer; n++) cc[n]='.';   // For debugging purposes (used fixed width font for testing)
        for (int n = left; n < right; n++) c[n] = tmp[n];
    }

    public void append(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (right + s.Length > bufferSize) increaseBuffer();

        // Append user input to buffer
        int len = s.Length;
        for (int n = 0; n < len; n++)
        {
            c[right] = s[n];
            right++;
        }
    }
    public void prepend(string s)
    {
        // If necessary, increase buffer size by growMultiplier
        while (left - s.Length < 0) increaseBuffer();               

        // Prepend user input to buffer
        int len = s.Length - 1;
        for (int n = len; n > -1; n--)
        {
            left--;
            c[left] = s[n];
        }
    }
    public void truncate(int start, int finish)
    {
        if (start < 0) throw new Exception("Truncation error: Start < 0");
        if (left + finish > right) throw new Exception("Truncation error: Finish > string length");
        if (finish < start) throw new Exception("Truncation error: Finish < start");

        //MessageBox.Show(left + " " + right);

        right = left + finish;
        left = left + start;
    }
    public string subString(int start, int finish)
    {
        if (start < 0) throw new Exception("Substring error: Start < 0");
        if (left + finish > right) throw new Exception("Substring error: Finish > string length");
        if (finish < start) throw new Exception("Substring error: Finish < start");
        return toString(start,finish);
    }

    public override string ToString()
    {
        return new string(c, left, right - left);
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
    private string toString(int start, int finish)
    {
        return new string(c, left+start, finish-start );
        //return new string(cc, 0, buffer);     // For debugging purposes (used fixed width font for testing)
    }
}

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