C# 或 Java:使用 StringBuilder 预先设置字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/738950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:17:20  来源:igfitidea点击:

C# or Java: Prepend strings with StringBuilder?

c#javastringbuilder

提问by burnt1ce

I know we can append strings using StringBuilder. Is there a way we can prepend strings (i.e. add strings in front of a string) using StringBuilderso we can keep the performance benefits that StringBuilderoffers?

我知道我们可以使用StringBuilder. 有没有一种方法可以StringBuilder让我们在字符串之前添加字符串(即在字符串前面添加字符串),以便我们可以保持所StringBuilder提供的性能优势?

采纳答案by driis

Using the insert method with the position parameter set to 0 would be the same as prepending (i.e. inserting at the beginning).

使用将 position 参数设置为 0 的 insert 方法与前置(即在开头插入)相同。

An example is: varStringBuilder.insert(0, "someThing");

一个例子是: varStringBuilder.insert(0, "someThing");

It works both for C#and Java

它适用于C#Java

回答by s_hewitt

Here's what you can do If you want to prepend using Java's StringBuilder class:

如果您想预先使用 Java 的 StringBuilder 类,您可以执行以下操作:

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

回答by boj

Try using Insert()

尝试使用Insert()

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

回答by Joachim Sauer

Prepending a String will usually require copying everything after the insertion point back some in the backing array, so it won't be as quick as appending to the end.

前置字符串通常需要将插入点之后的所有内容复制回支持数组中的一些内容,因此它不会像附加到末尾那样快。

But you can do it like this in Java (in C# it's the same, but the method is called Insert):

但是您可以在 Java 中这样做(在 C# 中它是相同的,但该方法被称为Insert):

aStringBuilder.insert(0, "newText");

回答by Shawn

If I understand you correctly, the insert methodlooks like it'll do what you want. Just insert the string at offset 0.

如果我理解正确的话,插入方法看起来就像你想要的那样。只需在偏移量 0 处插入字符串。

回答by Mark Maxham

You could try an extension method:

您可以尝试扩展方法:

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

回答by Tom Hawtin - tackline

If you require high performance with lots of prepends, you'll need to write your own version of StringBuilder(or use someone else's). With the standard StringBuilder(although technically it could be implemented differently) insert require copying data after the insertion point. Inserting n piece of text can take O(n^2) time.

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

A naive approach would be to add an offset into the backing char[]buffer as well as the length. When there is not enough room for a prepend, move the data up by more than is strictly necessary. This can bring performance back down to O(n log n) (I think). A more refined approach is to make the buffer cyclic. In that way the spare space at both ends of the array becomes contiguous.

一种天真的方法是将偏移量添加到后备char[]缓冲区以及长度。当没有足够的空间用于前置时,将数据向上移动超过绝对必要的数量。这可以将性能降低到 O(n log n)(我认为)。更精细的方法是使缓冲区循环。这样,阵列两端的空闲空间就变得连续了。

回答by Sam Barnum

I haven't used it but Ropes For JavaSounds intriguing. The project name is a play on words, use a Ropeinstead of a Stringfor serious work. Gets around the performance penalty for prepending and other operations. Worth a look, if you're going to be doing a lot of this.

我没用过,但Ropes For Java听起来很有趣。项目名称是文字游戏,认真工作时使用绳子而不是字符串。绕过前置和其他操作的性能损失。值得一看,如果你要做很多这样的事情。

A rope is a high performance replacement for Strings. The datastructure, described in detail in "Ropes: an Alternative to Strings", provides asymptotically better performance than both String and StringBuffer for common string modifications like prepend, append, delete, and insert. Like Strings, ropes are immutable and therefore well-suited for use in multi-threaded programming.

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

回答by bright

You could build the string in reverse and then reverse the result. You incur an O(n) cost instead of an O(n^2) worst case cost.

您可以反向构建字符串,然后反转结果。您招致 O(n) 成本而不是 O(n^2) 最坏情况成本。

回答by Dan W

Judging from the other comments, there's no standard quick way of doing this. Using StringBuilder's .Insert(0, "text")is approximately only 1-3x as fast as using painfully slow String concatenation (based on >10000 concats), so below is a class to prepend potentially thousands of times quicker!

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

I've included some other basic functionality such as append(), subString()and length()etc. Both appends and prepends vary from about twice as fast to 3x slower than StringBuilder appends. Like StringBuilder, the buffer in this class will automatically increase when the text overflows the old buffer size.

我已经包括了其他一些基本的功能,如append()subString()length()等双方追加,并预置约两倍快3倍不等慢于StringBuilder的追加。与 StringBuilder 一样,当文本溢出旧缓冲区大小时,此类中的缓冲区会自动增加。

The code has been tested quite a lot, but I can't guarantee it's free of bugs.

代码已经过大量测试,但我不能保证它没有错误。

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