web-dev-qa-db-fra.com

Couper les espaces à la fin d'un StringBuilder sans appeler ToString (). Trim () et revenir à un nouveau SB

Quel est un moyen efficace de réduire les espaces à partir de la fin d'une StringBuilder sans appeler ToString (). Trim () et revenir à un nouveau SB new StringBuilder(sb.ToString().Trim())

19
Nicholas Petersen

Ce qui suit est une méthode d'extension, vous pouvez donc l'appeler comme ceci:

    sb.TrimEnd();

En outre, il retourne l'instance SB, vous permettant de chaîner d'autres appels (sb.TrimEnd().AppendLine()).

    public static StringBuilder TrimEnd(this StringBuilder sb)
    {
        if (sb == null || sb.Length == 0) return sb;

        int i = sb.Length - 1;
        for (; i >= 0; i--)
            if (!char.IsWhiteSpace(sb[i]))
                break;

        if (i < sb.Length - 1)
            sb.Length = i + 1;

        return sb;
    }

Remarques:

1) Si Null ou Vide, retourne.

2) Si aucun ajustement n’est réellement nécessaire, nous parlons d’un temps de retour très rapide, l’appel le plus coûteux étant probablement l’appel unique à char.IsWhiteSpace. Donc, pratiquement aucune dépense d'appeler TrimEnd quand elle n'est pas nécessaire, par opposition à ces ToString (). Trim () aux routes SB.

3) Sinon, la chose la plus chère, si trim est nécessaire, sont les multiples appels à char.IsWhiteSpace (coupures sur le premier caractère non-blanc). Bien sûr, la boucle itère en arrière; si tous sont des espaces, vous obtiendrez un SB.Length de 0.

4) Si des espaces sont rencontrés, l’indice i est conservé en dehors de la boucle, ce qui nous permet de couper la longueur de manière appropriée avec elle. Dans StringBuilder, cela est incroyablement performant, il définit simplement un entier de longueur interne (le caractère interne [] est conservé à la même longueur interne).

UPDATE2: voir les excellentes notes de Ryan Emerle comme suit, qui corrigent certains de mes malentendus (le fonctionnement interne de SB est un peu plus compliqué que ce que je pensais être):

Techniquement, StringBuilder est une liste chaînée de blocs de caractères [], donc Ne se retrouve pas dans le LOH. Le réglage de la longueur n’est pas techniquement aussi simple que , Il s’agit de changer l’indice de fin, car si vous passez à un bloc Différent, la capacité doit être conservée, il peut donc être nécessaire de conserver le nouveau bloc. ] alloué. Néanmoins, vous définissez uniquement la propriété Length à la fin, . Cela semble donc être une excellente solution. Des détails pertinents d'Eric Lippert: https://stackoverflow.com/a/6524401/ 62195

Voir également cet article intéressant sur la nouvelle implémentation de .NET 4.0 StringBuilder: http://1024strongoxen.blogspot.com/2010/02/net-40-stringbuilder-implementation.html

------- METTRE À JOUR --------

Ce qui suit illustre ce qui se produit lorsqu’une longueur de StringBuilder est modifiée (la seule opération réelle effectuée sur le SB ici, et uniquement lorsque cela est nécessaire):

        StringBuilder sb = new StringBuilder("cool  \t \r\n ");

        sb.Capacity.Print(); // 16
        sb.Length.Print();  // 11

        sb.TrimEnd();

        sb.Capacity.Print(); // 16
        sb.Length.Print();  // 4 

Vous pouvez voir que le tableau interne (m_ChunkChars) reste à la même taille après avoir changé la longueur, et en fait, vous pouvez voir dans le débogueur qu'il n'écrase même pas les caractères (dans ce cas des espaces). Ils sont orphelins, c'est tout. 

32
Nicholas Petersen

Vous pouvez essayer ceci:

StringBuilder b = new StringBuilder();
b.Append("some words");
b.Append(" to test   ");

int count = 0;
for (int i = b.Length - 1; i >= 0; i--)
{
    if (b[i] == ' ')
        count++;
    else
        break;
}

b.Remove(b.Length - count, count);
string result = b.ToString();

Il faudra simplement parcourir la fin jusqu'à ce qu'il y ait des espaces, puis sortir de la boucle.

Ou même comme ça:

StringBuilder b = new StringBuilder();
b.Append("some words");
b.Append(" to test   ");

do
{
    if(char.IsWhiteSpace(b[b.Length - 1]))
    {
         b.Remove(b.Length - 1,1);
    }
}
while(char.IsWhiteSpace(b[b.Length - 1]));

string get = b.ToString();
3
terrybozzio
StringBuilder myString = new StringBuilder("This is Trim test ");

if (myString[myString.Length - 1].ToString() == " ")
{              
    myString = myString.Remove(myString.Length - 1, 1);
}
0
Muhammad Faisal