如何使用 StringBuilder 预置字符串?

我知道我们可以使用 StringBuilder附加字符串。有没有一种方法可以使用 StringBuilder来预置字符串(即在字符串前面添加字符串) ,这样我们就可以保持 StringBuilder提供的性能优势?

94153 次浏览

使用将位置参数设置为0的插入方法将与前置操作(即在开始处插入)相同。

C # 示例: varStringBuilder.Insert(0, "someThing");

Java 例子: varStringBuilder.insert(0, "someThing");

它既适用于 C # 也适用于 爪哇咖啡

如果你想预先使用 Java 的 StringBuilder 类,你可以这样做:

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

尝试使用 插入()

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

预置 String 通常需要将插入点之后的所有内容复制回备份数组中的某些内容,因此它不会像追加到末尾那样快。

但是你可以在 Java 中这样做(在 C # 中是一样的,但是这个方法叫做 Insert) :

aStringBuilder.insert(0, "newText");

如果我没理解错的话 插入法看起来可以满足你的要求。只需在偏移量0处插入字符串。

你可以试试扩展方法:

/// <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!

如果需要使用大量 prepend 来实现高性能,则需要编写自己的 StringBuilder版本(或使用其他人的版本)。使用标准的 StringBuilder(尽管在技术上可以采用不同的实现方式) ,插入需要在插入点之后复制数据。插入 n 段文本需要 O (n ^ 2)的时间。

一种简单的方法是在后备 char[]缓冲区中添加一个偏移量以及长度。当没有足够的空间进行预处理时,将数据向上移动多于严格必要的位置。这可以将性能降低到 O (n log n)(我认为)。更精确的方法是使缓冲区循环。这样,数组两端的空闲空间就变成了连续的。

我还没用过,但 爪哇的绳子听起来很有趣。该项目的名称是一个玩文字,使用一个 绳子而不是一个 绳子的严重工作。绕过预置操作和其他操作的性能损失。值得一看,如果你要做很多这个。

绳子是高性能的 字符串的替换 中详细描述的数据结构 “绳子: 弦的替代品” 提供渐近更好的 比 String 和 常用字符串的 StringBuffer 修改,例如附加,附加, 删除,然后插入,就像字符串一样, 绳子是不可改变的,因此 非常适合在多线程中使用 编程。

您可以反向构建字符串,然后反向构建结果。 产生 O (n)代价,而不是 O (n ^ 2)最坏情况下的代价。

从其他评论来看,没有标准的快速方法可以做到这一点。使用 StringBuilder 的 .Insert(0, "text")大约只有使用非常缓慢的字符串连接(基于 > 10000 concats)的速度的1-3倍,所以下面是一个可以快上数千倍的预先准备的类!

我已经包括一些其他的基本功能,如 append()subString()length()等。追加和附加的速度都比 StringBuilder 快两倍到三倍不等。与 StringBuilder 类似,当文本溢出旧的缓冲区大小时,该类中的缓冲区将自动增大。

这段代码已经被测试了很多次,但是我不能保证它没有 bug。

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

这应该会奏效:

aStringBuilder = "newText" + aStringBuilder;

您可以用一个简单的类为 StringBuilder 创建一个扩展:

namespace Application.Code.Helpers
{
public static class StringBuilderExtensions
{
#region Methods


public static void Prepend(this StringBuilder sb, string value)
{
sb.Insert(0, value);
}


public static void PrependLine(this StringBuilder sb, string value)
{
sb.Insert(0, value + Environment.NewLine);
}


#endregion
}
}

然后,加上:

using Application.Code.Helpers;

在任何希望使用 StringBuilder 的类的顶部,以及任何使用 StringBuilder 变量的智能方法时,都会显示 Prepend 和 PreendLine 方法。只要记住,当你使用 Prepend 时,你需要按照与 Appending 相反的顺序到达 Prepend。