C # або Java: додайте рядки за допомогою StringBuilder?


102

Я знаю, що ми можемо додавати рядки за допомогою StringBuilder. Чи існує спосіб, коли ми можемо додавати рядки (тобто додавати рядки перед рядком), використовуючи, StringBuilderщоб ми могли зберегти переваги від продуктивності StringBuilder?


Я не розумію вашого запитання
Моріс Перрі

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

Відповіді:


164

Використання методу вставки з параметром позиції, встановленим на 0, буде таким самим, як і попереднє (тобто вставлення на початку).

Приклад: varStringBuilder.insert(0, "someThing");

Він працює як для C #, так і для Java


7
StringBuilder вставка для java: java.sun.com/j2se/1.5.0/docs/api/java/lang/…
Matthew Farwell

Правильний 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
Це працює лише в тому випадку, якщо ви додаєте окремі символи. В іншому випадку вам потрібно буде змінити кожен доданий рядок, який би з'їв більшість, якщо не всю економію, залежно від розміру та кількості рядків.
Санки

4

Я не використовував його, але інтригує звуки Ropes For Java . Назва проекту - це гра на слова, використовуйте мотузку замість струни для серйозної роботи. Отримує покарання за виконання за попередні та інші операції. Варто поглянути, якщо ви збираєтеся багато цього робити.

Мотузка - це високоефективна заміна струн. Структура даних, детально описана в "Ropes: Альтернатива струнним", забезпечує асимптотично більшу продуктивність, ніж String і StringBuffer для звичайних модифікацій рядків, таких як додавання, додавання, видалення та вставка. Як і струнні, мотузки незмінні і тому добре підходять для використання в багатопотоковому програмуванні.


4

Ось що ви можете зробити, якщо ви хочете зробити попереднє використання класу StringBuilder Java:

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

3

Якщо я вас правильно зрозумів, метод вставки виглядає так, що він буде робити те, що ви хочете. Просто вставте рядок зі зміщенням 0.


2

Спробуйте використовувати Insert ()

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

2

Судячи з інших коментарів, немає стандартного швидкого способу зробити це. Використання StringBuilder's .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 в зворотному порядку, ніж якщо ви додавали.


0

Це має працювати:

aStringBuilder = "newText" + aStringBuilder; 

У .NET це прекрасно працює зі значеннями типу string, але не працює зі значеннями типу StringBuilder. Відповідь від @ScubaSteve працює добре.
Контанго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.