C # или Java: добавить строки с помощью StringBuilder?


104

Я знаю, что мы можем добавлять строки, используя StringBuilder. Есть ли способ, которым мы можем добавить строки (т.е. добавить строки перед строкой), используя, StringBuilderчтобы мы могли сохранить предлагаемые преимущества производительности StringBuilder?


Я не понимаю вашего вопроса
Морис Перри

5
Подготовить. Слово добавлено. Полагаю, предварительное добавление строки должно быть чем-то вроде добавления сразу к обоим концам строки?
Джоэл Мюллер,

Ответы:


166

Использование метода вставки с параметром позиции, установленным на 0, будет таким же, как добавление в начале (т.е. вставка в начало).

Пример: varStringBuilder.insert(0, "someThing");

Работает как для C #, так и для Java.



Правильный JavaDoc для соответствующего API: docs.oracle.com/javase/1.5.0/docs/api/java/lang/…
Sled

29

Добавление строки обычно требует копирования всего, что находится после точки вставки, обратно в массиве поддержки, поэтому это будет не так быстро, как добавление в конец.

Но в Java можно сделать так (в C # то же самое, но метод вызывается Insert):

aStringBuilder.insert(0, "newText");

11

Если вам требуется высокая производительность с большим количеством препендов, вам нужно будет написать свою собственную версию StringBuilder(или использовать чужую). Со стандартомStringBuilder вставке (хотя технически она может быть реализована иначе) для вставки требуется копирование данных после точки вставки. Вставка n фрагментов текста может занять время O (n ^ 2).

Наивный подход заключался бы в добавлении смещения в char[]буфер поддержки, а также длины. Если места для добавления не хватает, переместите данные на большее значение, чем это строго необходимо. Это может снизить производительность до O (n log n) (я думаю). Более совершенный подход - сделать буфер циклическим. Таким образом, свободное пространство на обоих концах массива становится непрерывным.


5

Вы можете попробовать метод расширения:

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

5

Вы можете построить строку в обратном порядке, а затем обратить результат. Вы понесете стоимость O (n) вместо затрат O (n ^ 2) в худшем случае.


2
Это работает, только если вы добавляете отдельные символы. В противном случае вам придется перевернуть каждую добавленную вами строку, что съест большую, если не всю экономию в зависимости от размера и количества строк.
Sled

4

Я не использовал его, но Ropes For Java звучит интригующе. Название проекта - игра слов, для серьезной работы используйте веревку вместо струны . Обходит снижение производительности за добавление и другие операции. Стоит взглянуть, если вы собираетесь много заниматься этим.

Веревка - это эффективная замена струнам. Структура данных, подробно описанная в статье «Веревки: альтернатива строкам», обеспечивает асимптотически лучшую производительность, чем String и StringBuffer, для общих модификаций строк, таких как добавление, добавление, удаление и вставка. Как и строки, связки неизменяемы и поэтому хорошо подходят для использования в многопоточном программировании.


4

Вот что вы можете сделать, если хотите добавить в начало класса Java StringBuilder:

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


2

Попробуйте использовать Insert ()

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

2

Судя по другим комментариям, стандартного быстрого способа сделать это не существует. Использование StringBuilder .Insert(0, "text")примерно в 1–3 раза быстрее, чем использование мучительно медленной конкатенации строк (на основе> 10000 конкатенаций), поэтому ниже приведен класс, который потенциально может добавлять в тысячи раз быстрее!

Я включил некоторые другие базовые функции, такие как append(), subString()и length()т. Д. И добавление, и добавление различаются от примерно в два раза быстрее до 3 раз медленнее, чем добавления 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)
    }
}

1

Вы можете сами создать расширение для 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, и каждый раз, когда вы используете intelli-sense с переменной StringBuilder, будут отображаться методы Prepend и PrependLine. Просто помните, что, когда вы используете Prepend, вам нужно будет Prepend в обратном порядке, чем если бы вы использовали Appending.


0

Это должно работать:

aStringBuilder = "newText" + aStringBuilder; 

В .NET это прекрасно работает со значениями типа string, но не работает со значениями типа StringBuilder. Ответ от @ScubaSteve работает хорошо.
Contango
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.