C # atau Java: Tambahkan string dengan StringBuilder?

102

Saya tahu kita bisa menambahkan string menggunakan StringBuilder. Adakah cara agar kita dapat menambahkan string (yaitu menambahkan string di depan string) menggunakan StringBuildersehingga kita dapat mempertahankan keunggulan kinerja yang StringBuilderditawarkan?

burnt1ce
sumber
Saya tidak mengerti pertanyaan Anda
Maurice Perry
5
Tambahkan di awal. Kata itu ada di depan. Preappending string harus seperti menambahkan ke kedua ujung string sekaligus, kurasa?
Joel Mueller

Jawaban:

29

Mempersiapkan String biasanya memerlukan penyalinan semuanya setelah titik penyisipan kembali beberapa di larik pendukung, sehingga tidak akan secepat menambahkan ke bagian akhir.

Tetapi Anda dapat melakukannya seperti ini di Java (di C # itu sama, tetapi metodenya disebut Insert):

aStringBuilder.insert(0, "newText");
Joachim Sauer
sumber
11

Jika Anda membutuhkan kinerja tinggi dengan banyak tambahan, Anda harus menulis versi Anda sendiri StringBuilder(atau menggunakan versi orang lain). Dengan standarStringBuilder (meskipun secara teknis dapat diimplementasikan secara berbeda), penyisipan memerlukan penyalinan data setelah titik penyisipan. Memasukkan n bagian teks dapat memakan waktu O (n ^ 2).

Pendekatan yang naif adalah dengan menambahkan offset ke dalam backing char[]buffer serta panjangnya. Jika tidak ada cukup ruang untuk tambahan, pindahkan data lebih dari yang benar-benar diperlukan. Ini dapat membawa kinerja kembali ke O (n log n) (saya pikir). Pendekatan yang lebih halus adalah membuat buffer siklik. Dengan cara itu, ruang kosong di kedua ujung larik menjadi bersebelahan.

Tom Hawtin - tackline
sumber
5

Anda dapat mencoba metode ekstensi:

/// <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!
Mark Maxham
sumber
5

Anda bisa membuat senar secara terbalik dan kemudian membalikkan hasilnya. Anda dikenakan biaya O (n) dan bukan biaya kasus terburuk O (n ^ 2).

terang
sumber
2
Itu hanya berfungsi jika Anda menambahkan karakter individu. Jika tidak, Anda perlu membalikkan setiap string yang Anda tambahkan yang akan memakan sebagian besar jika tidak semua penghematan tergantung pada ukuran dan jumlah string.
Kereta luncur
4

Saya belum pernah menggunakannya tetapi Ropes For Java Kedengarannya menarik. Nama proyek adalah permainan kata-kata, gunakan Rope sebagai ganti String untuk pekerjaan serius. Mendapat penalti kinerja untuk persiapan dan operasi lainnya. Layak untuk dilihat, jika Anda akan melakukan banyak hal seperti ini.

Tali adalah pengganti berkinerja tinggi untuk String. Struktur data, yang dijelaskan secara mendetail di "Ropes: an Alternative to Strings", memberikan kinerja yang lebih baik secara asimtotik daripada String dan StringBuffer untuk modifikasi string umum seperti menambahkan, menambahkan, menghapus, dan menyisipkan. Seperti String, tali tidak dapat diubah dan oleh karena itu cocok untuk digunakan dalam pemrograman multi-utas.

Sam Barnum
sumber
4

Inilah yang dapat Anda lakukan jika Anda ingin menambahkan kelas StringBuilder Java:

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

Jika saya memahami Anda dengan benar, metode sisipkan sepertinya akan melakukan apa yang Anda inginkan. Masukkan saja string pada offset 0.

Shawn
sumber
2

Coba gunakan Sisipkan ()

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

Dilihat dari komentar lain, tidak ada cara cepat standar untuk melakukan ini. Menggunakan StringBuilder's.Insert(0, "text") kira-kira hanya 1-3x lebih cepat daripada menggunakan penggabungan String yang sangat lambat (berdasarkan> 10000 concat), jadi di bawah ini adalah kelas untuk menambahkan potensi ribuan kali lebih cepat!

Saya telah menyertakan beberapa fungsi dasar lainnya seperti append(), subString()danlength() lain lain. Kedua appends dan prepends bervariasi dari sekitar dua kali lebih cepat hingga 3x lebih lambat daripada yang ditambahkan StringBuilder. Seperti StringBuilder, buffer di kelas ini akan meningkat secara otomatis saat teks melebihi ukuran buffer yang lama.

Kode telah diuji cukup banyak, tetapi saya tidak dapat menjamin bebas dari 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)
    }
}
Dan W.
sumber
1

Anda dapat membuat ekstensi untuk StringBuilder sendiri dengan kelas sederhana:

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

Lalu, tambahkan saja:

using Application.Code.Helpers;

Di bagian atas setiap kelas tempat Anda ingin menggunakan StringBuilder dan setiap kali Anda menggunakan intelli-sense dengan variabel StringBuilder, metode Prepend dan PrependLine akan muncul. Ingatlah bahwa saat Anda menggunakan Tambahkan ke Awal, Anda perlu Menambahkan Awal dalam urutan terbalik daripada jika Anda Menambahkan.

ScubaSteve
sumber
0

Ini harus bekerja:

aStringBuilder = "newText" + aStringBuilder; 
gok-nine
sumber
Di .NET, ini berfungsi sempurna dengan nilai tipe string, tetapi tidak berfungsi dengan nilai tipe StringBuilder. Jawaban dari @ScubaSteve berfungsi dengan baik.
Contango