web-dev-qa-db-fra.com

C # ou Java: ajouter des chaînes avec StringBuilder?

Je sais que nous pouvons ajouter des chaînes en utilisant StringBuilder. Existe-t-il un moyen de pré-ajouter des chaînes (c'est-à-dire d'ajouter des chaînes devant une chaîne) en utilisant StringBuilder afin que nous puissions conserver les avantages de performances que StringBuilder offre?

94
burnt1ce

L'utilisation de la méthode d'insertion avec le paramètre de position réglé sur 0 serait la même chose que le préfixe (c'est-à-dire l'insertion au début).

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

Il fonctionne à la fois pour C # et Java

149
driis

La pré-extension d'une chaîne nécessitera généralement de tout copier après le point d'insertion dans le tableau de support, donc ce ne sera pas aussi rapide que d'ajouter à la fin.

Mais vous pouvez le faire comme ceci dans Java (en C # c'est la même chose, mais la méthode s'appelle Insert):

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

Si vous avez besoin de hautes performances avec beaucoup de préfixes, vous devrez écrire votre propre version de StringBuilder (ou utiliser celle de quelqu'un d'autre). Avec la norme StringBuilder (bien que techniquement elle puisse être implémentée différemment), l'insertion nécessite la copie des données après le point d'insertion. L'insertion de n morceau de texte peut prendre O (n ^ 2).

Une approche naïve serait d'ajouter un décalage dans le support char[] buffer ainsi que la longueur. Lorsqu'il n'y a pas assez de place pour un préfixe, déplacez les données de plus que ce qui est strictement nécessaire. Cela peut ramener les performances à O (n log n) (je pense). Une approche plus raffinée consiste à rendre le tampon cyclique. De cette façon, l'espace disponible aux deux extrémités de la matrice devient contigu.

10

Vous pouvez essayer une méthode d'extension:

/// <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
Mark Maxham

Voici ce que vous pouvez faire si vous souhaitez ajouter un préfixe à l'aide de la classe StringBuilder de Java:

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

Je ne l'ai pas utilisé mais Ropes For Java Sons intrigants. Le nom du projet est un jeu de mots, utilisez une corde au lieu d'une chaîne pour un travail sérieux. Contourne la pénalité de performance pour les opérations de pré-paiement et autres. Ça vaut le coup, si vous allez faire beaucoup de cela.

Une corde est un remplacement de haute performance pour les cordes. La structure de données, décrite en détail dans "Cordes: une alternative aux chaînes", offre des performances asymptotiquement meilleures que String et StringBuffer pour les modifications de chaîne courantes telles que l'ajout, l'ajout, la suppression et l'insertion. Comme les cordes, les cordes sont immuables et donc bien adaptées à une utilisation en programmation multi-thread.

4
Sam Barnum

Vous pouvez créer la chaîne en sens inverse, puis inverser le résultat. Vous encourez un coût O(n) au lieu d'un coût O (n ^ 2) dans le pire des cas.

4
bright

Si je vous comprends bien, la insérer la méthode semble faire ce que vous voulez. Insérez simplement la chaîne à l'offset 0.

3
Shawn

À en juger par les autres commentaires, il n'y a pas de moyen rapide standard de le faire. L'utilisation de la fonction .Insert(0, "text") de StringBuilder est environ 1 à 3 fois plus rapide que la concaténation de chaînes douloureusement lente (basée sur> 10000 concats), donc ci-dessous se trouve une classe à ajouter potentiellement des milliers de fois plus rapidement!

J'ai inclus d'autres fonctionnalités de base telles que append(), subString() et length() etc. Les ajouts et les ajouts varient d'environ deux fois plus vite à 3 fois plus lentement que StringBuilder ajoute. Comme StringBuilder, le tampon de cette classe augmentera automatiquement lorsque le texte déborde de l'ancienne taille de tampon.

Le code a été beaucoup testé, mais je ne peux pas garantir qu'il est exempt de bogues.

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)
    }
}
2
Dan W

Essayez d'utiliser Insert ()

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

Vous pouvez créer vous-même une extension pour StringBuilder avec une classe simple:

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

Ensuite, ajoutez simplement:

using Application.Code.Helpers;

En haut de toute classe dans laquelle vous souhaitez utiliser StringBuilder et à chaque fois que vous utilisez intelli-sense avec une variable StringBuilder, les méthodes Prepend et PrependLine s'affichent. N'oubliez pas que lorsque vous utilisez Prepend, vous devrez Prepend dans l'ordre inverse que si vous ajoutiez.

1
ScubaSteve

Cela devrait fonctionner:

aStringBuilder = "newText" + aStringBuilder; 
0
gok-nine